Обработка изображений средствами PHP
PHP приобрел всемирную популярность не только как удобное средство вывода HTML и обработки форм, но и, во многом, благодаря набору расширений, позволяющим выполнять всевозможные стоящие перед веб-разработчиком задачи. Одним из таких расширений является библиотека GD, предназначенная для работы с растровыми изображениями. В этой статье мы рассмотрим работу со второй версией библиотеки GD. СборкаДля успешного выполнения примеров из этой статьи необходимо, чтобы PHP был собран с поддержкой второй версии библиотеки GD. Для того, чтобы узнать наличие и используемую версию графической библиотеки, воспользуемся всеми нами, без сомнения, любимой функцией phpinfo(), и взглянем на раздел "GD": gd
Если ничего похожего вы не нашли - значит, PHP собран без поддержки графической библиотеки, и придется его пересобирать (или попросить об этом админа). В противном случае, сначала взглянем на строку "GD Version". Если версия GD - первая (например, 1.6), то часть материала этой статьи вам не подойдет (и, в любом случае, рекомендую обновиться до второй версии). Вторая же версия тоже может быть разная. :) Обратите внимание на слово "bundled". Его присуствие означает, что PHP собран с библиотекой GD, поставляемой вместе с PHP: именно эту библиотеку рекомендуется использовать, так как разработчики PHP исправили множество ошибок и недочетов, присущих оригинальной GD. Впрочем, если используется внешняя библиотека (слово "bundled" в строке "GD Version" отсутствует) - ничего страшного, все приведенные ниже примеры будут работать. В нижеследующих строках мы видим, какие графические форматы поддерживаются данной конфигурацией библиотеки GD. В частности, работа с форматом GIF поддерживается в режиме "только чтение" из-за проблем с лицензированием используемого в GIF алгоритма компрессии. Итак, если требуется пересборка PHP, следует это и сделать, загрузив при необходимости последнюю версию PHP, и указать при сборке параметр: -with-gd[=location] Необязательный параметр location указывает путь к внешней библиотеке GD. Если его опустить (в смысле, не указывать) - используется bundled-версия. Для поддержки работы с шрифтами TrueType, обсуждаемой в главе "Вывод текста...", также понадобится наличие библиотеки FreeType и следующие параметры конфигурационной строки: -enable-gd-native-ttf Примечание: Для сборки GD с поддержкой GIF Write под FreeBSD, необходимо предварительно установить переменную среды WITH_LZW: Примечание 2:Выше подразумевалось, что используется Unix-подобная ОС. Если же PHP установлен локально, да еще и под Windows - то надо просто раскомментить одну строчку в php.ini - надеюсь, догадаетесь, какую. :) Генерация изображения с помощью PHPНу что ж, со сборкой PHP мы разобрались, и теперь нам не терпится нарисовать и вывести в броузер какую-нибудь картинку с помощью PHP. Надеюсь, вы прекрасно осознаете, что нельзя вот так вот просто взять и вывести картинку посреди HTML-кода в том же самом скрипте (если не осознаете, прочтите внимательно эту статью): в HTML-документе мы разместим, как и обычно, тэг , а в его атрибуте src укажем не картинку, как обычно, а PHP-скрипт: Теперь приступим к написанию этого самого image.php. Заголовок. Он же header.Прежде всего, как броузер узнает, что image.php - это не HTML-документ и не что-то еще, а картинка? Тип документа броузер определяет по заголовку Content-type. На самом деле, этот заголовок - обязательный и всегда присуствует; по умолчанию, PHP услужливо "отдает" заголовок Content-type: text/html. Обычно это поведение PHP нам прекрасно подходит - но не в данном случае. Придется нам вывести нужный заголовок самим:
Приступим теперь непосредственно к генерации картинки. Создание изображенияДля создания изображения, в нашем распоряжении две функции: 1. imagecreate(). С помощью этой функции можно создать изображение на основе палитры, содержащей фиксированный набор цветов. Каждый цвет палитры необходимо описать с помощью функции imagecolorallocate(). Этот способ создания изображения был единственным при работе с первой версией GD, и необходим при работе с ориентированными на палитру форматами, такими как GIF. Однако введенный во второй версии (и отныне рекомендуемый разработчиками) способ, на мой взгляд, гораздо более удобен. 2. imagecreatetruecolor(). Эта функция создает TrueColor-изображение, то есть цвет каждой точки определяется произвольным цветом, задаваемым в координатах RGB. Помимо того, что это удобнее, чем работа с палитрой, такой подход позволяет производить масштабирование изображения с гораздо меньшими потерями качества. Но об этом позже. Сейчас просто создадим изображение:
Функция imagecreatetruecolor (как, кстати, и функция imagecreate), принимает два обязательных целочисленных параметра - ширину (в нашем примере - 80 пикселей) и высоту (60 пикселей) картинки, и возвращает идентификатор ресурса (в данном случае - изображения), который мы присваиваем переменной $image, которой в дальнейшем будем постоянно пользоваться. Если по какой-либо страшной причине (недостатке памяти, например) создать изображение не получается, функция возвращает false - в этом случае мы прерываем работу скрипта. Хотя мы с этим изображением, пока что, ничего не делаем, мы обязаны освободить выделенную для него память с помощью функции imagedestroy(): к сожалению, автоматическое освобождение памяти происходит не всегда, и игнорирование рекомендации всегда использовать imagedestroy может привести к весьма серьезным утечкам памяти. Немножко порисуемИтак, с помощью функции imagecreatetruecolor() мы создали "труколорное" и, если верить документации, черное изображение размером 80x60. Так что, те, в чьи планы входит создание Web-галереи репродукций "квадрата Малевича", могут смело переходить к следующей главе. :) Для остальных, продолжим. Нарисуем на картинке что-нибудь содержательное. $image = imagecreatetruecolor(80,60) // создаем изображение... or die('Cannot create image'); // ...или прерываем работу скрипта в случае ошибки Палка, палка, огуречик, вот и вышел человечек :) Используемые для рисования функции весьма просты для понимания. Их описание (как и описание всех GD-функций) вы найдете здесь. В случае трудностей с английским, просто "поиграйтесь", меняя значения параметров - как вы, несомненно, уже догадались, это ни что иное, как координаты, и цвета в виде 0xRRGGBB. Подробнее же мы разберем вот эту строку: Выше мы создали в памяти изображение, и всячески над ним извращались. :) Это мы делали без привязки к какому-либо выходному формату - просто работали с набором байтов в памяти. А вот функции вида imageформат (imagepng(), imagejpeg(), imagewbmp()...) генерируют на основе этого самого набора байтов, на который ссылается идентификатор $image, картинку в соответствующем формате, и выводят ее в выходной поток - то бишь, проще говоря, в броузер. Нелишне здесь вспомнить и о строке header('Content-type: image/png'), где мы указали тип документа - обратите внимание: здесь png, и там png. :) Справедливости ради, надо заметить, что большинство броузеров воспринимают только часть "image" этого заголовка, а формат самой картинки уже определяют по ее заголовкам, характерным для каждого формата; однако, лучше все же не надеяться на "интеллект" броузера и указывать правильный формат изображения. Вывод текста, а также диаграммы и коллекционеры марокИспользуя полученные в результате рисования смайликов знания, попробуем порисовать диаграммы, а заодно и научимся выводить на картинках текст (не забудьте только о библиотеке FreeType, о необходимости наличия которой сказано в главе "Сборка". Предположим, вы располагаете следующей важной статистической информацией о коллекционерах почтовых марок:
...и горите желанием представить эту информацию в виде "столбиков" - для удобного сравнения. Столбики мы рисовать уже умеем - стоит только немножко вспомнить азы арифметики: define('GRAPH_WIDTH', 400); // ширина картинки define('GRAPH_HEIGHT', 300); // высота картинки define('GRAPH_OFFSET_TOP', 40); // отступ сверху define('GRAPH_OFFSET_LEFT', 40); // отступ слева define('GRAPH_OFFSET_RIGHT', 5); // отстут справа define('GRAPH_OFFSET_BOTTOM', 30); // отступ снизу Обратите внимание на строку Так зачем же, скажете вы, нам какие-то там TrueType-шрифты и FreeType-библиотеки, если мы и так прекрасно пишем на картинке? А вот затем, скажу я вам, что писать-то мы хотим по-русски, а встроенные шрифты о существовании кириллицы даже и не подозревают. А нам надо бы подписать столбики именно по-русски. Да и выбор встроенных шрифтов невелик. Итак, нам понадобится: - Функция imagettftext(), которая рисует выбранным TrueType-шрифтом на картинке, - Какой-нибудь кириллический TrueType-шрифт. Возьмем, например, arial.ttf из всеми нами любимой Винды, да не просто возьмем, а положим его туда, где лежит наш скрипт, - Поскольку функция imagettftext() воспринимает кодировку Unicode, но никак не Windows-1251, то нам пригодится вот такая функция для соответствующего преобразования:
- Функция imagettfbbox(), которая поможет нам вычислить высоту и ширину выводимого шрифтом текста. Сначала потренируемся: require('win2uni.php'); Тренировка прошла успешно - всех поприветствовали. Можно теперь приступать к нашим диаграммам. define('GRAPH_WIDTH', 400); // ширина картинки define('GRAPH_HEIGHT', 300); // высота картинки define('GRAPH_OFFSET_TOP', 40); // отступ сверху define('GRAPH_OFFSET_LEFT', 40); // отступ слева define('GRAPH_OFFSET_RIGHT', 5); // отстут справа define('GRAPH_OFFSET_BOTTOM', 30); // отступ снизу Барабанная дробь... Запускаем... Изменение размера: thumbnails, или "превьюшки"Часто перед веб-разработчиком стоит задача генерации уменьшенных копий изображений для предварительного просмотра; можно даже сказать, что это - одно из самых распространенных применений библиотеки GD. В GD1, поддерживающей только изображения на основе палитры, присуствовала лишь функция imagecopyresized(); качество уменьшенных изображений, генерируемых этой ей, мягко говоря, оставляло желать лучшего: работая с фиксированной палитрой, ограниченной 255 цветами, весьма затруднительно обеспечить качественный антиалиасинг. Во второй версии библиотеки, с появлением поддержки TrueColor и imagecreatetruecolor(), введена новая функция - imagecopyresampled(), обеспечивающая весьма достойное качество "превьюшек". Продемонстрируем работу с этой функцией. Предположим, у нас есть файл original.jpg, допустим, 400x250 пикселей, и мы хотим создать ее уменьшенный вариант small.jpg - 100x60. Можно поступить так: define('SOURCE', 'original.jpg'); // исходный файл define('TARGET', 'small.jpg'); // имя файла для "превьюшки" define('NEWX', 100); // ширина "превьюшки" define('NEWY', 60); // высота "превьюшки" Этот код работает, однако искажения, получаемые при непропорциональном изменении размера, выглядят не особенно симпатично. Более того, код получился не особенно-то универсальным: мало того, что мы можем работать только с JPEG-файлами, у нас еще и жестко заданы имена файлов и размеры получаемого изображения. Итак, пусть у нас есть файл в любом поддерживаемом GD формате, и мы хотим создать "превьюшку" заданного размера в формате JPEG. Разработаем для этой цели функцию imgResize. Комментариев здесь почти не будет - так как используются уже изученные приемы и обычная арифметика. Постарайтесь разобраться в этом коде самостоятельно.
Разобрались? Поместим этот код в файл imgresize.php. Пример использования функции img_resize: require ('imgresize.php'); if (img_resize('original.jpg', 'small.jpg', 100, 60)) echo 'Image resized OK'; else echo 'Resize failed!';
Страница сайта http://silicontaiga.ru
Оригинал находится по адресу http://silicontaiga.ru/home.asp?artId=6166 |