Журнал LinuxFormat - перейти на главную

LXF84:Python

Материал из Linuxformat
(Различия между версиями)
Перейти к: навигация, поиск
(Новая: {{цикл/Python}} == Python: Обработка графики и звука == ''ЧАСТЬ 4: Язык Python может многое, хотя, конечно, не всё. Но б...)
 
м (викификация)
 
Строка 7: Строка 7:
 
решил коротко остановиться на двух сторонних библиотеках, значительно расширяющих возможности Python по работе с изображениями и звуком.
 
решил коротко остановиться на двух сторонних библиотеках, значительно расширяющих возможности Python по работе с изображениями и звуком.
  
=== Где же кружка?... ===
+
=== Где же кружка?===
Начнем с PIL Python Image Library. Вам наверняка удастся без проблем инсталлировать ее с помощью менеджера пакетов вашего дистрибутива. Не исключено, что она уже установлена (как это имеет
+
Начнем с PIL Python Image Library. Вам наверняка удастся без проблем инсталлировать ее с помощью менеджера пакетов вашего дистрибутива. Не исключено, что она уже установлена (как это имеет
 
место быть в Ubuntu). Но если вам не очень повезло (мало ли, вдруг
 
место быть в Ubuntu). Но если вам не очень повезло (мало ли, вдруг
вы фанат Slackware), то забрать архив с ее исходным кодом можно
+
вы фанат Slackware), то забрать архив с ее исходным кодом можно
 
на http://www.Pythonware.com.
 
на http://www.Pythonware.com.
  
 
Итак, зачем она нужна? Представьте, что вы привезли с моря четыре «флешки», забитых замечательными фотографиями, и хотели бы
 
Итак, зачем она нужна? Представьте, что вы привезли с моря четыре «флешки», забитых замечательными фотографиями, и хотели бы
згрузить их на свою домашнюю страничку... Начинание благое, но
+
згрузить их на свою домашнюю страничку… Начинание благое, но
 
каково будет ее посетителям «тянуть» добродушно созданные вашей
 
каково будет ее посетителям «тянуть» добродушно созданные вашей
 
«Минолтой» файлы по 5 МБ каждый? Принципы гуманизма требуют
 
«Минолтой» файлы по 5 МБ каждый? Принципы гуманизма требуют
Строка 21: Строка 21:
 
взглядом сразу несколько фотографий.
 
взглядом сразу несколько фотографий.
  
Если вы уже собрались запускать Gimp одумайтесь! Ну на 10
+
Если вы уже собрались запускать Gimp одумайтесь! Ну на 10
изображений у вас терпения хватит, ну на 100... А если их 1000? Нет,
+
изображений у вас терпения хватит, ну на 100… А если их 1000? Нет,
 
ручная работа не для нас. Вот тут-то и пригодится PIL, где уже реализованы широчайшие возможности по обработке изображений.
 
ручная работа не для нас. Вот тут-то и пригодится PIL, где уже реализованы широчайшие возможности по обработке изображений.
  
Строка 95: Строка 95:
 
брать указанные с помощью шаблона файлы и сохранять их измененные копии в другом каталоге. PIL предоставляет много методов для
 
брать указанные с помощью шаблона файлы и сохранять их измененные копии в другом каталоге. PIL предоставляет много методов для
 
модификации изображений, в нашем примере мы остановимся на
 
модификации изображений, в нашем примере мы остановимся на
двух изменении размера и формата. Заодно вспомним, как работать
+
двух изменении размера и формата. Заодно вспомним, как работать
 
с файловой системой, и познакомимся с небольшим, но полезным
 
с файловой системой, и познакомимся с небольшим, но полезным
 
модулем getopt для разбора параметров, передаваемых сценарию из
 
модулем getopt для разбора параметров, передаваемых сценарию из
 
командной строки. Код сценария представлен в листинге conv2.py.
 
командной строки. Код сценария представлен в листинге conv2.py.
  
В строках 8–13 мы используем функцию getopt() одноименного модуля для того, чтобы получить передаваемые в скрипт опции.
+
В строках 8-13 мы используем функцию getopt() одноименного модуля для того, чтобы получить передаваемые в скрипт опции.
 
Первым параметром функция получает список аргументов командной строки (без первого элемента, соответствующего имени самого
 
Первым параметром функция получает список аргументов командной строки (без первого элемента, соответствующего имени самого
скрипта), а вторым список так называемых «коротких» опций, которые нужно найти. (Модуль поддерживает также и «длинные» опции в
+
скрипта), а вторым список так называемых «коротких» опций, которые нужно найти. (Модуль поддерживает также и «длинные» опции в
формате GNU смотрите документацию или код самого модуля). Если
+
формате GNU смотрите документацию или код самого модуля). Если
опция задается как логическая (т.е. важно лишь то, присутствует ли
+
опция задается как логическая (то есть важно лишь то, присутствует ли
она в командной строке), то в списке просто указывается соответствующая ей буква. Если опция параметрическая (т.е. должна сопровождаться каким-то значением), после ее буквы ставится двоеточие.
+
она в командной строке), то в списке просто указывается соответствующая ей буква. Если опция параметрическая (то есть должна сопровождаться каким-то значением), после ее буквы ставится двоеточие.
 
В нашем примере все опции параметрические: -t (формат выходных
 
В нашем примере все опции параметрические: -t (формат выходных
 
файлов), -o (каталог для их размещения), -h (высота модифицированного изображения), -w (ширина изображения).
 
файлов), -o (каталог для их размещения), -h (высота модифицированного изображения), -w (ширина изображения).
Строка 116: Строка 116:
 
изображений, их высоту или оба параметра сразу (если задан только
 
изображений, их высоту или оба параметра сразу (если задан только
 
один, второй вычисляется согласно пропорциям исходного файла, см.
 
один, второй вычисляется согласно пропорциям исходного файла, см.
строки 31–36).
+
строки 31-36).
  
 
Поскольку в опции -t пользователь может ввести все, что угодно, в
 
Поскольку в опции -t пользователь может ввести все, что угодно, в
строках 14–19 мы проводим небольшую проверку создаем изображение размером 1х1 и пытаемся записать его в /dev/null (чтобы нигде
+
строках 14-19 мы проводим небольшую проверку создаем изображение размером 1х1 и пытаемся записать его в /dev/null (чтобы нигде
 
мусор не разводить) в указанном пользователем формате type (метод
 
мусор не разводить) в указанном пользователем формате type (метод
save() самостоятельно выполняет все нужные преобразования форматов). В случае неудачи сообщаем об этом пользователю (обратите внимание на синтаксис перенаправления вывода по десткриптору, отличному от stdout). Если же операция пройдет успешно продолжаем.
+
save() самостоятельно выполняет все нужные преобразования форматов). В случае неудачи сообщаем об этом пользователю (обратите внимание на синтаксис перенаправления вывода по десткриптору, отличному от stdout). Если же операция пройдет успешно продолжаем.
  
 
Строки 20-25 отвечают за формирование списка файлов, соответствующих указанному шаблону. И, начиная с 26-й, мы приступаем собственно к обработке. Файлы, которые не могут быть открыты,
 
Строки 20-25 отвечают за формирование списка файлов, соответствующих указанному шаблону. И, начиная с 26-й, мы приступаем собственно к обработке. Файлы, которые не могут быть открыты,
например, текстовые, мы просто игнорируем строка 30.
+
например, текстовые, мы просто игнорируем строка 30.
  
 
В строке 37 изменяем размер изображения (при этом создается
 
В строке 37 изменяем размер изображения (при этом создается
Строка 130: Строка 130:
 
соседних точек (доступны и другие, например, LINEAR, NEAREST,
 
соседних точек (доступны и другие, например, LINEAR, NEAREST,
 
BICUBIC). Наконец, рассчитав имя результирующего файла, выполняем сохранение. В данном случае мы не передаем методу save() второй
 
BICUBIC). Наконец, рассчитав имя результирующего файла, выполняем сохранение. В данном случае мы не передаем методу save() второй
параметр, указывающий формат файла он будет определен автоматически по расширению.
+
параметр, указывающий формат файла он будет определен автоматически по расширению.
  
 
Вот, собственно, и готово:
 
Вот, собственно, и готово:
Строка 141: Строка 141:
 
</source>
 
</source>
 
Небольшой совет: вместо метода resize() для создания миниатюр
 
Небольшой совет: вместо метода resize() для создания миниатюр
лучше использовать метод thumbnail() он работает раза в два быстрее. Только имейте в виду, что thumbnail() изменяет текущий объект,
+
лучше использовать метод thumbnail() он работает раза в два быстрее. Только имейте в виду, что thumbnail() изменяет текущий объект,
т.е. исполняется «по месту», в то время как resize() создает копию объекта, оставляя оригинал в неприкосновенном виде (речь, естественно,
+
то есть исполняется «по месту», в то время как resize() создает копию объекта, оставляя оригинал в неприкосновенном виде (речь, естественно,
об объекте в памяти файл на диске не будет изменен до тех пор, пока
+
об объекте в памяти файл на диске не будет изменен до тех пор, пока
 
вы явно не выполните метод save()).
 
вы явно не выполните метод save()).
  
=== Не конвертированием единым... ===
+
=== Не конвертированием единым… ===
 
Естественно, возможности PIL этим не ограничиваются: она позволяет изменять цветовые схемы; применять к изображениям фильтры,
 
Естественно, возможности PIL этим не ограничиваются: она позволяет изменять цветовые схемы; применять к изображениям фильтры,
такие как размывание, рельеф и т.д. (см. модуль ImageFilter и метод
+
такие как размывание, рельеф и т. д. (см. модуль ImageFilter и метод
 
filter() модуля Image); вы можете смешивать различные изображения
 
filter() модуля Image); вы можете смешивать различные изображения
 
(методы blend() и composite()), поворачивать их на различные углы,
 
(методы blend() и composite()), поворачивать их на различные углы,
 
смещать, вырезать из них фрагменты, накладывать простейшие графические элементы (такие как линии и дуги, см. модуль ImageDraw),
 
смещать, вырезать из них фрагменты, накладывать простейшие графические элементы (такие как линии и дуги, см. модуль ImageDraw),
и т.д.
+
и т. д.
  
 
Вот так, например, можно в два раза усилить «красную» составляющую исходного изображения:
 
Вот так, например, можно в два раза усилить «красную» составляющую исходного изображения:
Строка 175: Строка 175:
 
Здесь методом split() мы раскладываем исходный объект на «цветовые» составляющие (если атрибут объекта, mode, подтверждает,
 
Здесь методом split() мы раскладываем исходный объект на «цветовые» составляющие (если атрибут объекта, mode, подтверждает,
 
что загруженный файл является RGB-изображением), методом point()
 
что загруженный файл является RGB-изображением), методом point()
применяем указанную функцию (в нашем случае - умножение на два)
+
применяем указанную функцию (в нашем случае умножение на два)
 
к каждому пикселу «красного» объекта, и с помощью merge() объединяем все снова в одно изображение.
 
к каждому пикселу «красного» объекта, и с помощью merge() объединяем все снова в одно изображение.
  
Строка 185: Строка 185:
 
контролировать промежуточные результаты.
 
контролировать промежуточные результаты.
  
=== Нам песня строить и жить помогает... ===
+
=== Нам песня строить и жить помогает… ===
 
{{Врезка
 
{{Врезка
 
|Заголовок=Листинг «playit.py»
 
|Заголовок=Листинг «playit.py»
Строка 224: Строка 224:
 
</source>
 
</source>
 
|Ширина=350px}}
 
|Ширина=350px}}
Следующая библиотека, которую мы затронем в этом уроке PyMedia.
+
Следующая библиотека, которую мы затронем в этом уроке PyMedia.
 
Скачать исходный код можно с сайта http://www.pymedia.org (там же вы найдете и документацию, и архив с примерами). Установка выполняется,
 
Скачать исходный код можно с сайта http://www.pymedia.org (там же вы найдете и документацию, и архив с примерами). Установка выполняется,
 
в принципе, достаточно просто:
 
в принципе, достаточно просто:
Строка 232: Строка 232:
 
admin@toshiba:~/PyMedia-1.3.7.3$ sudo Python setup.py install
 
admin@toshiba:~/PyMedia-1.3.7.3$ sudo Python setup.py install
 
</source>
 
</source>
Однако, среди зависимостей alsa, ogg, vorbis, faad, mp3lame
+
Однако, среди зависимостей alsa, ogg, vorbis, faad, mp3lame
(причем для инсталляции нужны и заголовочные файлы, т.е. может
+
(причем для инсталляции нужны и заголовочные файлы, то есть может
 
потребоваться доустановить соответствующие dev-пакеты). Также
 
потребоваться доустановить соответствующие dev-пакеты). Также
 
потребуется пакет Python-dev. Так что, если вам посчастливится
 
потребуется пакет Python-dev. Так что, если вам посчастливится
Строка 239: Строка 239:
 
здесь: http://prdownloads.sourceforge.net/PyMedia/PyMedia_1.3.5_i686-py2.4.deb?download), то рекомендую воспользоваться им.
 
здесь: http://prdownloads.sourceforge.net/PyMedia/PyMedia_1.3.5_i686-py2.4.deb?download), то рекомендую воспользоваться им.
  
На листинге «playit.py» представлен код класса, задача которого
+
На листинге «playit.py» представлен код класса, задача которого -
воспроизвести звуковой файл. Первыми строками (3–6) подключаем
+
воспроизвести звуковой файл. Первыми строками (3-6) подключаем
 
нужные нам модули (иерархия здесь довольно сложная, так что без
 
нужные нам модули (иерархия здесь довольно сложная, так что без
 
документации не обойтись; ну и про примеры не забывайте).
 
документации не обойтись; ну и про примеры не забывайте).
Строка 248: Строка 248:
 
создаем объект Demuxer, которому передается в качестве параметра
 
создаем объект Demuxer, которому передается в качестве параметра
 
расширение файла (строка 13). Этот объект мы используем для того,
 
расширение файла (строка 13). Этот объект мы используем для того,
чтобы декодировать заголовок звукового файла (в строках 14–16 мы
+
чтобы декодировать заголовок звукового файла (в строках 14-16 мы
 
считываем первые 32000 байт файла и передаем их методу parse()).
 
считываем первые 32000 байт файла и передаем их методу parse()).
 
Теперь мы можем определить идентификатор нужного кодека по ключу ‘id’ в словаре dm.streams[0] (строка 17; можно в качестве параметра
 
Теперь мы можем определить идентификатор нужного кодека по ключу ‘id’ в словаре dm.streams[0] (строка 17; можно в качестве параметра
 
передать и весь словарь), и используем этот кодек для декодирования
 
передать и весь словарь), и используем этот кодек для декодирования
уже считанных данных. Поскольку здесь, помимо всего прочего, присутствует и служебная информация, то после декодирования мы получаем возможность вывести кое-что из этого на экран (строки 19–23;
+
уже считанных данных. Поскольку здесь, помимо всего прочего, присутствует и служебная информация, то после декодирования мы получаем возможность вывести кое-что из этого на экран (строки 19-23;
но это только в тестовых целях в классах, которые могут использоваться в различных программах, оператору print, конечно, не место).
+
но это только в тестовых целях в классах, которые могут использоваться в различных программах, оператору print, конечно, не место).
  
 
В строке 24 создается объект Output, метод play() которого будет
 
В строке 24 создается объект Output, метод play() которого будет
 
использоваться для воспроизведения (строка 28). Изменив параметр
 
использоваться для воспроизведения (строка 28). Изменив параметр
rateCf, можно ускорить или замедлить проигрывание файла (по умолчанию используется значение 1). Наконец, в цикле (строки 27–30) мы
+
rateCf, можно ускорить или замедлить проигрывание файла (по умолчанию используется значение 1). Наконец, в цикле (строки 27-30) мы
 
воспроизводим уже считанный фрагмент (переменная s) и готовим
 
воспроизводим уже считанный фрагмент (переменная s) и готовим
 
следующий. Как только мы считаем и передим методу play() весь
 
следующий. Как только мы считаем и передим методу play() весь
Строка 268: Строка 268:
 
корректирующий скорость воспроизведения. Само воспроизведение
 
корректирующий скорость воспроизведения. Само воспроизведение
 
запускается методом playit(). Причем библиотека PyMedia вполне
 
запускается методом playit(). Причем библиотека PyMedia вполне
позволяет поигрывать одновременно несколько файлов - в качестве
+
позволяет поигрывать одновременно несколько файлов в качестве
 
примера рассмотрим, как можно получить простейший эффект объемного звука:
 
примера рассмотрим, как можно получить простейший эффект объемного звука:
  
Строка 291: Строка 291:
 
В этом сценарии мы запускаем два потока (если значение переменной ECHO отлично от нуля). В каждом из потоков проигрывается один
 
В этом сценарии мы запускаем два потока (если значение переменной ECHO отлично от нуля). В каждом из потоков проигрывается один
 
и тот же файл, но перед запуском второго делается небольшая пауза
 
и тот же файл, но перед запуском второго делается небольшая пауза
(в примере 0,1 секунды). В результате получается довольно интересное звучание. Кстати, обратите внимание на то, как мы запустили потоки вместо того, чтобы создавать соответствующий класс и переопределять в нем метод run(), был напрямую вызван «внутренний» метод
+
(в примере 0,1 секунды). В результате получается довольно интересное звучание. Кстати, обратите внимание на то, как мы запустили потоки вместо того, чтобы создавать соответствующий класс и переопределять в нем метод run(), был напрямую вызван «внутренний» метод
 
_start_new_thread(), которому передается функция или метод, которые
 
_start_new_thread(), которому передается функция или метод, которые
 
должны быть выполнены в потоке.
 
должны быть выполнены в потоке.
  
 
Помимо собственно воспроизведения звука, PyMedia предоставляет средства для работы с видео-файлами, ее можно использовать для
 
Помимо собственно воспроизведения звука, PyMedia предоставляет средства для работы с видео-файлами, ее можно использовать для
конвертирования исходного файла в другие форматы, для редактирования мета-данных и самого звука, и т.д.
+
конвертирования исходного файла в другие форматы, для редактирования мета-данных и самого звука, и т. д.
  
 
=== Малышка wave ===
 
=== Малышка wave ===
Строка 340: Строка 340:
 
Открыв wav-файл (строка 6), мы можем получить некоторую
 
Открыв wav-файл (строка 6), мы можем получить некоторую
 
информацию о нем (строки 7-11). Считываем данные в переменную
 
информацию о нем (строки 7-11). Считываем данные в переменную
normal (нормальная последовательность). «Сырой» wav-файл (т.е. без
+
normal (нормальная последовательность). «Сырой» wav-файл (то есть без
 
компрессии; подавляющее большинство таковыми и является) представляет собой набор «фреймов», или «отсчетов», то есть значений
 
компрессии; подавляющее большинство таковыми и является) представляет собой набор «фреймов», или «отсчетов», то есть значений
 
амплитуды сигнала в данный момент времени. Частота дискретизации
 
амплитуды сигнала в данный момент времени. Частота дискретизации
 
определяет, сколько фреймов будут формировать одну секунду звучания. Точность дискретизации показывает, сколько байт используется для хранения одного фрейма (значение 1 соответствует 8-битному
 
определяет, сколько фреймов будут формировать одну секунду звучания. Точность дискретизации показывает, сколько байт используется для хранения одного фрейма (значение 1 соответствует 8-битному
звуку, 2 16-битному).
+
звуку, 2 16-битному).
  
 
Для того чтобы развернуть наш файл, нужно «реверсировать» считанную нормальную последовательность. Это можно легко выполнить
 
Для того чтобы развернуть наш файл, нужно «реверсировать» считанную нормальную последовательность. Это можно легко выполнить
Строка 350: Строка 350:
 
мы работаем с 16-битным файлом, то нужно позаботиться о сохранении порядка байтов во фрейме, иначе получим лишь шум. Для этого в
 
мы работаем с 16-битным файлом, то нужно позаботиться о сохранении порядка байтов во фрейме, иначе получим лишь шум. Для этого в
 
строках 16 и 17 мы формируем две «подпоследовательности», в одну
 
строках 16 и 17 мы формируем две «подпоследовательности», в одну
из которых попадают младшие байты фреймов, во вторую старшие.
+
из которых попадают младшие байты фреймов, во вторую старшие.
 
С помощью функции map(), которая применяет функцию, указанную
 
С помощью функции map(), которая применяет функцию, указанную
 
первым параметром (в нашем примере это sum(), описанная в строках
 
первым параметром (в нашем примере это sum(), описанная в строках
4–5), к каждому элементу последовательностей, переданных вторым и
+
4-5), к каждому элементу последовательностей, переданных вторым и
 
третьим параметрами, мы соединяем полученные полуфреймы воедино. Поскольку на выходе map() получается список, то нам нужно его
 
третьим параметрами, мы соединяем полученные полуфреймы воедино. Поскольку на выходе map() получается список, то нам нужно его
вручную «собрать» снова в строку (стр. 18–19).
+
вручную «собрать» снова в строку (стр. 18-19).
  
 
Нужно заметить, что map() отличается очень высокой скоростью
 
Нужно заметить, что map() отличается очень высокой скоростью
Строка 378: Строка 378:
 
|Ширина=350px}}
 
|Ширина=350px}}
 
На этом мы завершаем нашу серию уроков. Благодаря тому, что разработчикам Python удалось сделать этот язык простым и в то же время
 
На этом мы завершаем нашу серию уроков. Благодаря тому, что разработчикам Python удалось сделать этот язык простым и в то же время
удивительно мощным и расширяемым, с его помощью можно эффективно решать самые различные задачи дополнительная сложность
+
удивительно мощным и расширяемым, с его помощью можно эффективно решать самые различные задачи дополнительная сложность
 
будет проявляться лишь там, где это действительно необходимо, в
 
будет проявляться лишь там, где это действительно необходимо, в
 
то время как простые задачи сохранят предельную простоту. И если
 
то время как простые задачи сохранят предельную простоту. И если
вдруг для какого-то проекта стандартных средств окажется недостаточно, то наверняка вам поможет какая-нибудь из сторонних библиотек. Главное не сдаваться!
+
вдруг для какого-то проекта стандартных средств окажется недостаточно, то наверняка вам поможет какая-нибудь из сторонних библиотек. Главное не сдаваться!
  
 
Удачи!
 
Удачи!

Текущая версия на 12:31, 22 июня 2008

Содержание

[править] Python: Обработка графики и звука

ЧАСТЬ 4: Язык Python может многое, хотя, конечно, не всё. Но благодаря «привязкам» к таким мощным библиотекам, как GTK и модулям сторонних разработчиков его возможности становятся практически безграничными, пишет Сергей Супрунов.

Рассказывать о различных «расширениях» Python можно бесконечно. Чтобы все-таки завершить серию и дать вам возможность погрузиться в самостоятельное изучение этого языка, я решил коротко остановиться на двух сторонних библиотеках, значительно расширяющих возможности Python по работе с изображениями и звуком.

[править] Где же кружка?…

Начнем с PIL — Python Image Library. Вам наверняка удастся без проблем инсталлировать ее с помощью менеджера пакетов вашего дистрибутива. Не исключено, что она уже установлена (как это имеет место быть в Ubuntu). Но если вам не очень повезло (мало ли, вдруг вы — фанат Slackware), то забрать архив с ее исходным кодом можно на http://www.Pythonware.com.

Итак, зачем она нужна? Представьте, что вы привезли с моря четыре «флешки», забитых замечательными фотографиями, и хотели бы згрузить их на свою домашнюю страничку… Начинание благое, но каково будет ее посетителям «тянуть» добродушно созданные вашей «Минолтой» файлы по 5 МБ каждый? Принципы гуманизма требуют предварительно «сжать» изображения до приемлемых размеров. Да и миниатюры создать было бы неплохо, чтобы можно было окинуть взглядом сразу несколько фотографий.

Если вы уже собрались запускать Gimp — одумайтесь! Ну на 10 изображений у вас терпения хватит, ну на 100… А если их 1000? Нет, ручная работа не для нас. Вот тут-то и пригодится PIL, где уже реализованы широчайшие возможности по обработке изображений.

[править] Небольшой практикум

Итак, после установки библиотеки все ее модули вы, скорее всего, найдете в /usr/lib/Python2.4/site-packages/PIL. Кстати, обычно при инсталляции PIL добавляет в список sys.path также и указанный путь, так что для подключения, скажем, модуля ImageDraw, можно будет использовать не только import PIL.ImageDraw, но и просто import ImageDraw.

Сами модули не слишком щедро прокомментированы, но зато по адресу http://www.Pythonware.com/library/pil/handbook вы найдете превосходное руководство.

Несмотря на множество модулей, входящих в состав библиотеки, для большинства задач вполне хватает модуля Image, а он уже сам неявно задействует возможности остальных. Основой является объект-изображение, которое можно загрузить из файла (используя метод open()), либо создать с нуля (конструктор new()), причем при загрузке файла библиотека сама позаботится о распознавании формата изображения.

Для примера напишем небольшой конвертер, который мог бы брать указанные с помощью шаблона файлы и сохранять их измененные копии в другом каталоге. PIL предоставляет много методов для модификации изображений, в нашем примере мы остановимся на двух — изменении размера и формата. Заодно вспомним, как работать с файловой системой, и познакомимся с небольшим, но полезным модулем getopt для разбора параметров, передаваемых сценарию из командной строки. Код сценария представлен в листинге conv2.py.

В строках 8-13 мы используем функцию getopt() одноименного модуля для того, чтобы получить передаваемые в скрипт опции. Первым параметром функция получает список аргументов командной строки (без первого элемента, соответствующего имени самого скрипта), а вторым — список так называемых «коротких» опций, которые нужно найти. (Модуль поддерживает также и «длинные» опции в формате GNU — смотрите документацию или код самого модуля). Если опция задается как логическая (то есть важно лишь то, присутствует ли она в командной строке), то в списке просто указывается соответствующая ей буква. Если опция параметрическая (то есть должна сопровождаться каким-то значением), после ее буквы ставится двоеточие. В нашем примере все опции параметрические: -t (формат выходных файлов), -o (каталог для их размещения), -h (высота модифицированного изображения), -w (ширина изображения).

Возвращает getopt() два списка: список распознанных опций в формате [(опция, значение), (опция, значение), (. . .)] (значение указывается только для параметрический опций, для логических второй элемент кортежа остается пустым), и список оставшихся (не распознанных) аргументов. Наш скрипт будет ожидать во втором списке имена файлов (с указанием пути, если нужно), которые должны быть преобразованы. Пользователь может задать ширину результирующих изображений, их высоту или оба параметра сразу (если задан только один, второй вычисляется согласно пропорциям исходного файла, см. строки 31-36).

Поскольку в опции -t пользователь может ввести все, что угодно, в строках 14-19 мы проводим небольшую проверку — создаем изображение размером 1х1 и пытаемся записать его в /dev/null (чтобы нигде мусор не разводить) в указанном пользователем формате type (метод save() самостоятельно выполняет все нужные преобразования форматов). В случае неудачи сообщаем об этом пользователю (обратите внимание на синтаксис перенаправления вывода по десткриптору, отличному от stdout). Если же операция пройдет успешно — продолжаем.

Строки 20-25 отвечают за формирование списка файлов, соответствующих указанному шаблону. И, начиная с 26-й, мы приступаем собственно к обработке. Файлы, которые не могут быть открыты, например, текстовые, мы просто игнорируем — строка 30.

В строке 37 изменяем размер изображения (при этом создается новый объект). Флаг Image.ANTIALIAS задает способ интерполяции соседних точек (доступны и другие, например, LINEAR, NEAREST, BICUBIC). Наконец, рассчитав имя результирующего файла, выполняем сохранение. В данном случае мы не передаем методу save() второй параметр, указывающий формат файла — он будет определен автоматически по расширению.

Вот, собственно, и готово:

admin@toshiba:~/lxf/propy/l4/code$ ./conv2.py -t png -h 120 *.jpg
osf_t1.jpg (JPEG, 2272x1704) -> ./osf_t1.png (png, 160x120)
osf_t2.jpg (JPEG, 2272x1704) -> ./osf_t2.png (png, 160x120)
osf_t3.jpg (JPEG, 2272x1704) -> ./osf_t3.png (png, 160x120)
osf_t4.jpg (JPEG, 2272x1704) -> ./osf_t4.png (png, 160x120)

Небольшой совет: вместо метода resize() для создания миниатюр лучше использовать метод thumbnail() — он работает раза в два быстрее. Только имейте в виду, что thumbnail() изменяет текущий объект, то есть исполняется «по месту», в то время как resize() создает копию объекта, оставляя оригинал в неприкосновенном виде (речь, естественно, об объекте в памяти — файл на диске не будет изменен до тех пор, пока вы явно не выполните метод save()).

[править] Не конвертированием единым…

Естественно, возможности PIL этим не ограничиваются: она позволяет изменять цветовые схемы; применять к изображениям фильтры, такие как размывание, рельеф и т. д. (см. модуль ImageFilter и метод filter() модуля Image); вы можете смешивать различные изображения (методы blend() и composite()), поворачивать их на различные углы, смещать, вырезать из них фрагменты, накладывать простейшие графические элементы (такие как линии и дуги, см. модуль ImageDraw), и т. д.

Вот так, например, можно в два раза усилить «красную» составляющую исходного изображения:

ЛИСТИНГ MAXIRED.PY

#!/usr/bin/Python
# -*- coding: utf-8 -*-
 
import os, sys, Image
 
infile = sys.argv[1]
im = Image.open(infile)
if im.mode == “RGB”:
 imR, imG, imB = im.split()
 imR = imR.point(lambda pixel: pixel * 2)
 outfile = Image.merge(“RGB”, (imR, imG, imB))
 outfile.save(%s-red%s” % os.path.splitext(infile))
else:
 print >> sys.stderr, “ОШИБКА: файл не RGB”

Здесь методом split() мы раскладываем исходный объект на «цветовые» составляющие (если атрибут объекта, mode, подтверждает, что загруженный файл является RGB-изображением), методом point() применяем указанную функцию (в нашем случае — умножение на два) к каждому пикселу «красного» объекта, и с помощью merge() объединяем все снова в одно изображение.

Нужно заметить, что библиотека PIL предназначена для обработки изображений, а не для их вывода. Если вы хотите вставить фотографию в ваше графическое приложение, для этого следует использовать средства соответствующего модуля. Например, в Tkinter для этого предназначены классы BitmapImage и PhotoImage. Есть, конечно, и в PIL метод show(), но он просто сохраняет объект во временный файл и отдает его внешней программе просмотра изображений (xv под Unix/Linux, Paint в Windows), поэтому пригоден он разве что для отладочных целей, чтобы по ходу разработки скрипта можно было «на лету» контролировать промежуточные результаты.

[править] Нам песня строить и жить помогает…

Следующая библиотека, которую мы затронем в этом уроке — PyMedia. Скачать исходный код можно с сайта http://www.pymedia.org (там же вы найдете и документацию, и архив с примерами). Установка выполняется, в принципе, достаточно просто:

admin@toshiba:~$ tar xzvf PyMedia-1.3.7.3.tar.gz
admin@toshiba:~$ cd PyMedia-1.3.7.3
admin@toshiba:~/PyMedia-1.3.7.3$ sudo Python setup.py install

Однако, среди зависимостей — alsa, ogg, vorbis, faad, mp3lame (причем для инсталляции нужны и заголовочные файлы, то есть может потребоваться доустановить соответствующие dev-пакеты). Также потребуется пакет Python-dev. Так что, если вам посчастливится найти для своего дистрибутива двоичный пакет библиотеки (в частности, deb-пакет, правда, не самой новой версии, можно найти здесь: http://prdownloads.sourceforge.net/PyMedia/PyMedia_1.3.5_i686-py2.4.deb?download), то рекомендую воспользоваться им.

На листинге «playit.py» представлен код класса, задача которого - воспроизвести звуковой файл. Первыми строками (3-6) подключаем нужные нам модули (иерархия здесь довольно сложная, так что без документации не обойтись; ну и про примеры не забывайте).

Сначала мы должны определить идентификатор кодека, который подойдет для воспроизведения того или иного файла. Для этого мы создаем объект Demuxer, которому передается в качестве параметра расширение файла (строка 13). Этот объект мы используем для того, чтобы декодировать заголовок звукового файла (в строках 14-16 мы считываем первые 32000 байт файла и передаем их методу parse()). Теперь мы можем определить идентификатор нужного кодека по ключу ‘id’ в словаре dm.streams[0] (строка 17; можно в качестве параметра передать и весь словарь), и используем этот кодек для декодирования уже считанных данных. Поскольку здесь, помимо всего прочего, присутствует и служебная информация, то после декодирования мы получаем возможность вывести кое-что из этого на экран (строки 19-23; но это только в тестовых целях — в классах, которые могут использоваться в различных программах, оператору print, конечно, не место).

В строке 24 создается объект Output, метод play() которого будет использоваться для воспроизведения (строка 28). Изменив параметр rateCf, можно ускорить или замедлить проигрывание файла (по умолчанию используется значение 1). Наконец, в цикле (строки 27-30) мы воспроизводим уже считанный фрагмент (переменная s) и готовим следующий. Как только мы считаем и передим методу play() весь файл, в строке 31 начнется ожидание конца воспроизведения (что-бы не сильно нагружать процессор, проверку выполняем один раз в секунду). Ожидание нужно, поскольку play() является асинхронным методом, который возвращает управление сценарию до того, как воспроизведение фрагмента на самом деле завершится. Благодаря этому мы можем спокойно обрабатывать следующий фрагмент, не беспокоясь о паузах при воспроизведении.

Для использования класса playit нужно создать соответствующий объект, передав ему имя файла и, при желании, коэффициент, корректирующий скорость воспроизведения. Само воспроизведение запускается методом playit(). Причем библиотека PyMedia вполне позволяет поигрывать одновременно несколько файлов — в качестве примера рассмотрим, как можно получить простейший эффект объемного звука:

Листинг echo.py

#!/usr/bin/Python
from playit import playit
import threading, time
mp3 = ‘Aria.shtil.mp3’
ECHO = 0.1
f1 = playit(mp3)
f1.rateCf = 1
ht1 = threading._start_new_thread(f1.playit, ())
if ECHO:
time.sleep(ECHO)
f2 = playit(mp3)
f2.rateCf = 1
ht2 = threading._start_new_thread(f2.playit, ())
while(f1.PLAY_FLG or ECHO and f2.PLAY_FLG):
time.sleep(1)

В этом сценарии мы запускаем два потока (если значение переменной ECHO отлично от нуля). В каждом из потоков проигрывается один и тот же файл, но перед запуском второго делается небольшая пауза (в примере — 0,1 секунды). В результате получается довольно интересное звучание. Кстати, обратите внимание на то, как мы запустили потоки — вместо того, чтобы создавать соответствующий класс и переопределять в нем метод run(), был напрямую вызван «внутренний» метод _start_new_thread(), которому передается функция или метод, которые должны быть выполнены в потоке.

Помимо собственно воспроизведения звука, PyMedia предоставляет средства для работы с видео-файлами, ее можно использовать для конвертирования исходного файла в другие форматы, для редактирования мета-данных и самого звука, и т. д.

[править] Малышка wave

Кстати, раз уж зашла речь об обработке звука, то и в стандартной поставке Python есть несколько модулей для выполнения простейших операций. Например, модуль wave позволяет редактировать (и даже создавать с нуля, если вы сильны в математике) звуковые файлы в формате WAV. На листинге wav2.py представлен сценарий, с помощью которого можно «развернуть» wav-файл в обратном направлении:

Открыв wav-файл (строка 6), мы можем получить некоторую информацию о нем (строки 7-11). Считываем данные в переменную normal (нормальная последовательность). «Сырой» wav-файл (то есть без компрессии; подавляющее большинство таковыми и является) представляет собой набор «фреймов», или «отсчетов», то есть значений амплитуды сигнала в данный момент времени. Частота дискретизации определяет, сколько фреймов будут формировать одну секунду звучания. Точность дискретизации показывает, сколько байт используется для хранения одного фрейма (значение 1 соответствует 8-битному звуку, 2 — 16-битному).

Для того чтобы развернуть наш файл, нужно «реверсировать» считанную нормальную последовательность. Это можно легко выполнить с помощью списковых включений (как показано в строке 21). Но если мы работаем с 16-битным файлом, то нужно позаботиться о сохранении порядка байтов во фрейме, иначе получим лишь шум. Для этого в строках 16 и 17 мы формируем две «подпоследовательности», в одну из которых попадают младшие байты фреймов, во вторую — старшие. С помощью функции map(), которая применяет функцию, указанную первым параметром (в нашем примере это sum(), описанная в строках 4-5), к каждому элементу последовательностей, переданных вторым и третьим параметрами, мы соединяем полученные полуфреймы воедино. Поскольку на выходе map() получается список, то нам нужно его вручную «собрать» снова в строку (стр. 18-19).

Нужно заметить, что map() отличается очень высокой скоростью обработки последовательностей. Если собирать результирующую строку «вручную» (например, в цикле while), то эта процедура может затянуться на десятки секунд даже для не очень большого файла, в то время как map() выполняет эту операцию почти мгновенно.

Наконец, в строках 22-26 мы открываем новый файл на запись, устанавливаем его параметры (в соответствии с исходными) и записываем содержимое. Теперь можете и сами поиграть в «АПОП»!

[править] Только вперед!

На этом мы завершаем нашу серию уроков. Благодаря тому, что разработчикам Python удалось сделать этот язык простым и в то же время удивительно мощным и расширяемым, с его помощью можно эффективно решать самые различные задачи — дополнительная сложность будет проявляться лишь там, где это действительно необходимо, в то время как простые задачи сохранят предельную простоту. И если вдруг для какого-то проекта стандартных средств окажется недостаточно, то наверняка вам поможет какая-нибудь из сторонних библиотек. Главное — не сдаваться!

Удачи!

Персональные инструменты
купить
подписаться
Яндекс.Метрика