Профессиональная разработка Web-приложений. [email-masked]

Материалы 2-й PHP конференции в PHPInside#5

| Новости | Статьи | База скриптов
| Вопрос-Ответ | Форумы
| Биржа труда
| О нас |
Книги |

Новости

PDF журнал

Участники проектa

Сотрудничество

Ссылки

Карта сайта

Web Architect WorkShop Day 8окт
Мастер-классы для WEB-архитекторов

PHPConf 2009 9окт
Авторы PHP, MySQL, ZEND, Sphinx, Pinba открывают секреты

Комментарии

Комментарии к статье

Добавить комментарий

Обсудить на форуме

Информация об авторе

Оценка статьи

PHPClub > PHP в деталях

Создание изображений средствами PHP

Версия для печати

Создание изображений средствами PHP

Тилл Геркен

28-02-2000

PHP не только идеально подходит для вывода
HTML страниц, но также включает в себя мощные средства создания
изображений "на лету".

Целевая аудитория

Введение

Цель этой статьи

Что нам потребуется

Создаем изображения

Как это выглядит на практике

Установка даты рождения

Подготовка изображения

Рисуем рамку и выводим текст

Рисуем кривые

Вывод изображения клиенту

Как использовать полученное изображение

Полный код скрипта

Ссылки

Заключение

Об авторе

Целевая аудитория

Эта статья рассчитано на программистов со средним уровнем знания PHP.

Введение

PHP не только идеально подходит для вывода HTML страниц, но также
включает в себя мощные средства создания изображений "на лету". Приведу
лишь несколько примеров:

Создание кнопок с надписями, текст которых хранится в базе данных

Графическое отображение статистических данных

Создание различных графиков и диаграмм

В этой статье рассматривается использование библиотеки GD для
обработки изображений. GD является внешней библиотекой, доступной в виде
модуля PHP

Цель этой статьи

В статье освещаются следующие вопросы:

Что такое заголовки (headers)

Использование функций библиотеки GD для динамического создания
изображений средствами PHP

Использование HTTP заголовков для указания браузеру, что вывод
PHP-скрипта представляет собой изображение

Создание заголовка

По умолчанию, PHP выводит один заголовок: Content-type:
text/html, означающий, что результатом работы скрипта является HTML
код

<?php

print("Hello world!");

?>

$> php hello.php

Content-type: text/html

Hello world!

$> _

Как видите, PHP выводит Content-type: text/html и пустую
строку, прежде чем выводить результат работы скрипта . Все до пустой строки
является заголовком HTTP. Заголовок содержит информацию для браузера и не
отображается на экране.

Используемый по умолчанию заголовок Content-type: text/html
показывает, что выводится HTML код, который браузер должен обработать.
Если изменить его скажем на Content-type: text/plain, то
браузер будет
воспринимать документ просто как текст и выводить его "как есть"
Для вывода заголовков в PHP используется функция
header().

<?php

header("Content-type: image/jpeg");  // выводим изображение в формате JPEG

header("Content-type: application/zip");    // выводим ZIP файл

?>

Конечно, послать заголовок недостаточно, нужно еще и позаботиться о
том, чтобы вывести данные в нужном формате. Не следует думать, что, просто
послав заголовок Content-type: application/zip и выведя "Всем привет", вы
сможете открыть результат работы такого скрипта с помощью WinZip'а.

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

Что нам потребуется

Создание изображений в PHP требует наличия библиотеки GD написанной
Thomas Boutell . (http://www.boutell.com/gd) Поддержка
этой библиотеки включается при компиляции PHP с опцией --with-gd. Для
работы с TrueType шрифтами также может понадобиться библиотека FreeType
(http://www.freetype.org). Установка
обеих библиотек подробно описана в соответствующей документации.

Создаем изображения

Генерация изображения состоит из трех основных этапов:

Создание изображения

Отрисовка изображения

Вывод полученной картинки в браузер

Для создания изображения используется функция ImageCreate().
В качестве аргументов функция принимает ширину и высоту изображения в
пикселах и возвращает идентификатор, который в дальнейшем используется
при вызове функция для работы с изображением.

Перед тем, как что-либо рисовать, необходимо зарегистрировать цвета,
которые вы собираетесь использовать. Для этого предназначена функция
ImageColorAllocate().
Этой функции передаются идентификатор изображения и три числа, задающие
цвет (RGB - red, green, blue). Функция возвращает идентификатор цвета,
который используется в последующих операциях отрисовки изображения.

Пример:

<?php

// регистрируем цвет

$colorHandle = imageColorAllocate($image, 192, 192, 192);

// используем для рисования

imageFilledRectangle($image, 0, 0, $diagramWidth - 1, $diagramHeight - 1, $colorBackgr);

?>

Существует большое количество функций отрисовки изображений. Полное их
рассмотрение выходит за рамки данной статьи. Для ознакомления с этими
функциями, обратитесь к руководству по PHP.

И, наконец, вывод изображения осуществляется вызовом функции ImagePNG()
или ImageGIF().
Последняя не поддерживается в текущей версии GD из-за проблем с
лицензированием (разработчики GD обещают возобновить поддержку формата
GIF после 7 июля 2004 года, когда истечет срок действия патентов Unisys на
алгоритм сжатия LZW, используемый в GIF. Уже после написания этой статьи в
библиотеку была включена поддержка форматов JPEG и WBMP. -прим.
переводчика). ImagePNG() преобразует внутреннее представление
изображения в PNG файл и посылает его клиенту. Аналогично работает и
ImageGIF(),
но используя формат GIF. Перед использованием функций ImagePNG()
или ImageGIF()
необходимо послать соответствующий заголовок Content-type

Формат

Заголовок

PNG

"Content-type: image/png"

GIF

"Content-type: image/gif"

Примечание
Заголовки относятся ко всему документу. То есть если вы послали заголовок,
показывающий, что вы выводите изображение, вы не можете выводить текст. А
после того, как вы вывели первый байт данных, заголовок уже нельзя
изменить! Это значит, что сначала нужно вызвать header() и
только затем начинать вывод данных, иначе вы получите сообщение об
ошибке. Если вы не посылаете заголовок Content-type, PHP
автоматически посылает Content-type: text/html как только вы
начинаете вывод данных.

Как это выглядит на практике

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

Теория биоритмов гласит, что эмоциональная, физическая и
интеллектуальная активность каждого человека циклически изменяются с
определенными интервалами. В момент рождения, все три кривые выходят из
нулевой точки и изменяются в течение всей жизни. Если кривая проходит выше
нулевой отметки - это активная фаза, ниже - пассивная. Момент
пересечения нулевой отметки означает критический день: вы подвержены риску
эмоциональной, физической или интеллектуальной "катастрофы". А в тот день,
когда все три кривые проходят через ноль, лучше вообще воздержаться от
работы над важными PHP проектами.

У каждой кривой собственный цикл:

Физическая: 23 дня

Эмоциональная: 28 дней

Интеллектуальная: 33 дня

Кривые представляют собой синусоиды, поэтому для вычисления значений
биоритмов мы можем воспользоваться встроенной функцией sin()

Установка даты рождения

Сначала мы должны получить дату рождения и вычислить, сколько дней
человек прожил до текущей даты. Результат будет использован для вычисления
текущей фазы биоритма.

Порядок действий

Проверяем, была ли введена дата рождения.

Если нет, отображаем форму для ввода даты

После проверки правильности ввода вычисляем сколько дней человек
прожил до текущей даты используя юлианский календарь.

<?php

if(!isset($birthdate))

{

/* */

}

$daysGone = abs(gregorianToJD($birthMonth, $birthDay, $birthYear)

- gregorianToJD(date( "m"), date( "d"), date( "Y")));

?>

Совет
Для вычисления мы используем юлианский календарь. Дата рождения и текущая
дата переводятся в количество дней по юлианскому календарю. Разность этих
двух чисел дает искомый результат.

Примечание
В этом примере функция gregorianToJD()
реализована на PHP (см. полный код скрипта ниже). Вообще-то, эта функция
реализована в календарном модуле PHP, но на момент написания этой статьи
эта функция работала некорректно в последней версии PHP. Поэтому была
использована "самодельная" функция.
Если в вашем PHP включена поддержка функций работы с календарем, вам нужно
удалить определение этой функции из кода в примере.

Подготовка изображения

Порядок действий
Подготовка к рисованию состоит из вызова нескольких функций GD. Следующий участок кода:

Создает изображение нужных размеров.

Регистрирует используемые цвета.

Очищает изображения, заливая его цветом фона

<?php

// создаем изображение

$image = imageCreate($diagramWidth, $diagramHeight);

// Регистрируем используемые цвета

$colorBackgr       = imageColorAllocate($image, 192, 192, 192);

$colorForegr       = imageColorAllocate($image, 255, 255, 255);

$colorGrid         = imageColorAllocate($image, 0, 0, 0);

$colorCross        = imageColorAllocate($image, 0, 0, 0);

$colorPhysical     = imageColorAllocate($image, 0, 0, 255);

$colorEmotional    = imageColorAllocate($image, 255, 0, 0);

$colorIntellectual = imageColorAllocate($image, 0, 255, 0);

// заливаем цветом фона

imageFilledRectangle($image, 0, 0, $diagramWidth - 1, $diagramHeight - 1, $colorBackgr);

?>

Совет
Перед началом отрисовки изображения залейте его цветом фона. Это
гарантирует, что фон изображения будет того цвета, что вам нужен. Это
также полезно для создания прозрачного фона, как будет показано далее.

Примечание
Для простоты изложения, примеры в этой статье не содержат проверок ошибок.
"Настоящий" скрипт обязательно должен включать проверки на ошибки

Рисуем рамку и выводим текст

Функция ImageString()
рисует строку текста на изображении в заданном месте. Нам необходимо
вывести пять строк Первые две будут находиться в верхней части рисунка и
отображать дату рождения и текущую дату, остальные три под графиком будут
показывать, каким цветом какой биоритм изображен. Использование
идентификаторов цветов, записанных в переменные, позволяет ссылаться на
цвета, не указывая каждый раз RGB значения.

Порядок действий

Рисуем рамку, внутри которой будет размещен график, и оси

Выводим текст примечаний

<?php

// рисуем рамку

imageRectangle($image, 0, 0, $diagramWidth - 1, $diagramHeight - 20,

$colorGrid);

// рисуем оси

imageLine($image, 0, ($diagramHeight - 20) / 2, $diagramWidth,

($diagramHeight - 20) / 2, $colorCross);

imageLine($image, $diagramWidth / 2, 0, $diagramWidth / 2, $diagramHeight - 20,

$colorCross);

// выводим текст

imageString($image, 3, 10, 10,  "Birthday: $birthDay.$birthMonth.$birthYear",

$colorCross);

imageString($image, 3, 10, 26,  "Today:    ".  date(  "d.m.Y"),  $colorCross);

imageString($image, 3, 10, $diagramHeight - 42,  "Physical", $colorPhysical);

imageString($image, 3, 10, $diagramHeight - 58,  "Emotional", $colorEmotional);

imageString($image, 3, 10, $diagramHeight - 74,  "Intellectual",

$colorIntellectual);

?>

Рисунок 1. График биоритмов

Рисуем кривые

Графики биоритмов представляют собой синусоиды, отличающиеся только
периодом, поэтому мы определяем функцию drawRythm() , которая отображает
синусоиду с заданным периодом. Эта функция будет вычислять значения
биоритмов для каждого дня в заданном периоде и соединять полученные точки
линиями.

Порядок действий

Функция drawRhythm вызывается три раза с различными параметрами

Функция drawRhythm содержит цикл, который вычисляет значение биоритма
для каждого дня, и рисует линии.

<?php

drawRhythm($daysGone, 23, $colorPhysical);

drawRhythm($daysGone, 28, $colorEmotional);

drawRhythm($daysGone, 33, $colorIntellectual);

for($x = 0; $x < $daysToShow; $x++)

{

// вычисление фазы синусоиды, соответствующей определенному дню

$phase = (($centerDay + $x) % $period) / $period * 2 * pi();

//  вычисление значения Y

$y = 1 - sin($phase) * (float)$plotScale + (float)$plotCenter;

// рисуем линию от предыдущей точки до текущей

if($x > 0)

imageLine($image, $oldX, $oldY, $x * $diagramWidth / $daysToShow,

$y, $color);

// сохраняем текущие координаты для использования в следующем проходе цикла

$oldX = $x * $diagramWidth / $daysToShow;

$oldY = $y;

}

?>

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

Вывод изображения клиенту

Итак, мы нарисовали наш график. Теперь остается отправить это
изображение в браузер.

Порядок действий

Посылаем заголовок, показывающий что мы выводим изображение в формате GIF или PNG.

Определяем чересстрочный формат вывода изображения.

Делаем цвет фона прозрачным.

Используя функцию imageGIF или
imagePNG
выводим изображение.

<?php

//header("Content-type:  image/gif");

header("Content-type:  image/png");

// задаем чересстрочный режим

imageInterlace($image, 1);

// делаем цвет фона прозрачным

imageColorTransparent($image, $colorBackgr);

//imageGIF($image);

imagePNG($image);

?>

Совет
После вызова imageGIF или
imagePNG,
изменения в изображение вносить уже нельзя, так как оно уже было
отправлено клиенту.

Использование ImageInterlace()
позволяет задать режим чересстрочного или прогрессивного вывода
изображения (если используемый формат изображения позволяет это). Этот
режим интересен тем, что позволяет браузеру начать отображение картинки
еще до ее полной загрузки. Сначала выводится изображение с низким
качеством, которое улучшается по мере загрузки данных. Это незаменимо при
передаче больших изображений по низкоскоростным каналам.

Функция ImageColorTransparent()
задает цвет прозрачных участков изображения (опять же, если используемый
формат позволяет это). В нашем примере мы используем цвет, сохраненный в
переменной $colorBackgr, делая участки изображения,
нарисованные этим цветом, прозрачными.

Как использовать полученное
изображение

Итак, мы написали программу, создающую изображение. Как ее
использовать? На самом деле все очень просто: Вы можете использовать
скрипт в HTML коде как обычный файл изображения. Поскольку скрипт в нашем
примере является интерактивным, то для его использования нам нужно ввести
http://my.server.net/script.php в адресную строку браузера. Для скрипта,
не требующего пользовательского ввода, например получающего информацию из
базы данных, просто вставьте в HTML код страницы тэг такого содержания:

<img src="http://my.server.net/script.php">

Полный код скрипта

<?php

//

// шапка страницы

//

function pageHeader()

{

print("<html><head>");

print("<title>Biorhythm with PHP3</title>");

print("</head><body>");

}

//

// подвал страницы

//

function pageFooter()

{

print("</body></html>");

}

//

// Функция преобразования даты по григорианскому календарю

// в юлианский календарь  (количество дней)

//

function gregorianToJD($month, $day, $year)

{

// За основу взят алгоритм

// Peter Baum, [email-masked]

if($month < 3)

{

$month = $month + 12;

$year = $year - 1;

}

$jd = $day + floor((153 * $month - 457) / 5) + 365 * $year

+ floor($year / 4) - floor($year / 100)

+ floor($year / 400) + 1721118.5;

return($jd);

}

//

// Функция отрисовки графика биоритма

// Параметры: номер дня, период биоритма и цвет

//

function drawRhythm($daysAlive, $period, $color)

{

global $daysToShow, $image, $diagramWidth, $diagramHeight;

// определим день в центре графика

$centerDay = $daysAlive - ($daysToShow / 2);

// параметры графика

$plotScale = ($diagramHeight - 25) / 2;

$plotCenter = ($diagramHeight - 25) / 2;

// рисуем график

for($x = 0; $x <= $daysToShow; $x++)

{

// вычисление фазы синусоиды, соответствующей определенному дню

$phase = (($centerDay + $x) % $period) / $period * 2 * pi();

//  вычисление значения Y

$y = 1 - sin($phase) * (float)$plotScale + (float)$plotCenter;

// рисуем линию от предыдущей точки до текущей

if($x > 0)

imageLine($image, $oldX, $oldY, $x * $diagramWidth / $daysToShow,

$y, $color);

// сохраняем текущие координаты для использования в следующем проходе цикла

$oldX = $x * $diagramWidth / $daysToShow;

$oldY = $y;

}

}

//

// ---- MAIN PROGRAM START ----

// Проверяем, была ли введена дата рождения.

// Если нет, отображаем форму для ввода даты

if(!isset($birthdate))

{

pageHeader();

?>

<form method="post" action="<?php print(basename($PHP_SELF)); ?>">

Please enter your birthday:<br>

<input type="text" name="birthdate"

value="MM/DD/YYYY"><input type="submit" value="OK!">

</form>

<?php

pageFooter();

exit();

}

// выделяем день, месяц и год

$birthMonth = substr($birthdate, 0, 2);

$birthDay = substr($birthdate, 3, 2);

$birthYear = substr($birthdate, 6, 4);

// Проверяем правильности ввода

if(!checkDate($birthMonth, $birthDay, $birthYear))

{

pageHeader();

print("The date '$birthMonth/$birthDay/$birthYear' is invalid.");

pageFooter();

exit();

}

// параметры графика (глобальные переменные)

$diagramWidth = 710;

$diagramHeight = 400;

$daysToShow = 30;

//определяем, сколько дней человек прожил до текущей даты используя юлианский календарь.

$daysGone = abs(gregorianToJD($birthMonth, $birthDay, $birthYear)

- gregorianToJD(date( "m"), date( "d"), date( "Y")));

// содаем изображение

$image = imageCreate($diagramWidth, $diagramHeight);

// Регистрируем используемые цвета

$colorBackgr       = imageColorAllocate($image, 192, 192, 192);

$colorForegr       = imageColorAllocate($image, 255, 255, 255);

$colorGrid         = imageColorAllocate($image, 0, 0, 0);

$colorCross        = imageColorAllocate($image, 0, 0, 0);

$colorPhysical     = imageColorAllocate($image, 0, 0, 255);

$colorEmotional    = imageColorAllocate($image, 255, 0, 0);

$colorIntellectual = imageColorAllocate($image, 0, 255, 0);

// заливаем цветом фона

imageFilledRectangle($image, 0, 0, $diagramWidth - 1, $diagramHeight - 1, $colorBackgr);

// вычисляем начальную дату графика

$nrSecondsPerDay = 60 * 60 * 24;

$diagramDate = time() - ($daysToShow / 2 * $nrSecondsPerDay) + $nrSecondsPerDay;

for ($i = 1; $i < $daysToShow; $i++)

{

$thisDate = getDate($diagramDate);

$xCoord = ($diagramWidth / $daysToShow) * $i;

// рисуем засечку на оси и номер дня

imageLine($image, $xCoord, $diagramHeight - 25, $xCoord,

$diagramHeight - 20, $colorGrid);

imageString($image, 3, $xCoord - 5, $diagramHeight - 16,

$thisDate[ "mday"], $colorGrid);

$diagramDate += $nrSecondsPerDay;

}

// рисуем рамку

imageRectangle($image, 0, 0, $diagramWidth - 1, $diagramHeight - 20,

$colorGrid);

// рисуем оси

imageLine($image, 0, ($diagramHeight - 20) / 2, $diagramWidth,

($diagramHeight - 20) / 2, $colorCross);

imageLine($image, $diagramWidth / 2, 0, $diagramWidth / 2, $diagramHeight - 20,

$colorCross);

// выводим текст

imageString($image, 3, 10, 10,  "Birthday: $birthDay.$birthMonth.$birthYear",

$colorCross);

imageString($image, 3, 10, 26,  "Today:    ".  date(  "d.m.Y"),  $colorCross);

imageString($image, 3, 10, $diagramHeight - 42,  "Physical", $colorPhysical);

imageString($image, 3, 10, $diagramHeight - 58,  "Emotional", $colorEmotional);

imageString($image, 3, 10, $diagramHeight - 74,  "Intellectual",

$colorIntellectual);

// рисуем три графика с соответствующими параметрами

drawRhythm($daysGone, 23, $colorPhysical);

drawRhythm($daysGone, 28, $colorEmotional);

drawRhythm($daysGone, 33, $colorIntellectual);

// Отправляем заголовок Content-type

//header("Content-type:  image/gif");

header("Content-type:  image/png");

// задаем чересстрочный режим

imageInterlace($image, 1);

// делаем цвет фона прозрачным

imageColorTransparent($image, $colorBackgr);

// и выводим изображение

//imageGIF($image);

imagePNG($image);

?>

Заключение

В данной статье рассмотрены основы создания изображений в PHP с
использованием функций графической библиотеки GD. На достаточно сложном
примере показано, как можно создавать изображения на основе ввода
пользователя. Взяв за основу этот пример, вы сможете создавать изображения
для решения ваших конкретных задач.

Ссылки

PHP

Библиотека GD

Библиотека Freetype

Справочник по
функциям PHP для обработки изображений

Информация об авторе и
контактная информация

Об авторе

Тилл Геркен (Till Gerken) является независимым разработчиком и
консультантом, работающим в различных компаниях. Он специализируется на
создании интернет приложений. Имеет более чем 10-летний опыт
программирования, начиная от высокопроизводительных мультимедиа систем,
таких как 3D-движки и звуковые микшеры с использованием C/C++, Pascal и
ассемблера x86, до сложных сайтов на основе PHP. Совместно с Тобиасом
Ратшиллером (Tobias Ratschiller) в настоящее время работает над книгой
PHP4: разработка Web-приложений которая планируется к выпуску
издательством New Riders в этом году (оригинальная статья было
опубликована в 2000 г. - прим. переводчика). Также принимает участие в
работе над сайтом http://www.phpwizard.net/. (в
настоящее время сайт неактивен - прим. переводчика)

Оригинал статьи находится на сайте
www.zend.com

Перевод Андрея Деменева

Наверх

For comment register here

Kolobok

2004-03-04 11:16

Вопрос такой:

А что ж тогда делать, если всетаки нужно получить картинку GIF?

Есть какие-нибудь другие модули?

decoder

2004-12-26 06:54

А если картника хранится у меня в БД.

Как мне ее тогда юзать?

st3pl3r

2005-02-17 14:14

здОрово, спасибо большое. было интересно.

Андреенко Артём

2005-04-26 18:33

А что на счёт того, чтобы изначально открыть существующую png, а потом на ней рисовать и выводить в поток клиенту?

Создание изображений на лету, Вывод изображения в PHP, примеры GD, PNG, imageGIF, PHP, Изображение, динамически, пример, графика в php

|

Новости |
Статьи |
База скриптов |
Вопрос-Ответ |
Форумы
| Биржа труда
| О нас |
Книги

© 1997-2008 PHPClubTeam

[]

Saved from http://phpclub.ru/detail/article/dynamic_image
Fri Dec 04 2009 12:34:40 GMT+0200 (FLE Standard Time)
Saved by UnMHT Ver.5.4.0