| Робота з зображеннями за допомогою PHP |
| П'ятниця, 29 січня 2010 17:16 | ||||||
PHP не лише ідеально підходить для виводу HTML сторінок, але також включає в себе потужні засоби створення зображень "на льоту". Наведу лише декілька прикладів: Створення кнопок з написами, текст яких зберігається в базі даних Графічне відображення статистичних даних Створення різноманітних графіків та діаграмВ цій статті розглядається використання бібліотеки GD для обробки зображень. GD являється зовнішньою бібліотекою, доступною у вигляді модуля PHP Ціль даної статтіВ статті освітлюються наступні питання:
Створення заголовкаЗа замовчуванням, PHP виводить один заголовок: Content-type: text/html, який означає, що результатом роботи скрипта являється HTML код. 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(). 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). Функція повертає ідентифікатор кольору, який використовується в подальших опареціях промальовки зображення. Приклад: // реєструємо колір $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
Примітка Заголовки відносяться до всього документу. Тобто якщо ви надіслали заголовок, який показує що ви виводите зображення, ви е можете виводити текст. А після того як ви вивели перший байт даних, заголовок вже неможна міняти! Це означає що спершу потрібно викликати header() і лише після цього починати вивід даних, інакше ви отримаєте повідомлення про помилку. Якщо ви не надсилаєте заголовок Content-type, PHP автоматично надсилає Content-type: text/html як тільки ви починаєте вивід даних. Як це виглядає на практиці Практичне використання функцій GD ми розглянемо на прикладі скрипта, який будує графік біоритмів. По ходу викладення будемо наводити уривки с коду скрипта, який повністю наведений вкінці сторінки. Теорія біоритмів полягає в тому, що емоційні, фізична і інтелектуальна діяльність кожної людини циклічно змінюється з певними інтервалами. В момент народження, всі три криві виходять з нульової точки і змінюються напротязі всього життя. Якщо крива проходить вище нульової позначки - це активна фаза, нижче - пасивна. Момент перетину нульової позначки означає критичний день: ви піддаєтесьб ризику емоційної, фізичної чи інтелектуальної "катастрофи". А в той день коли всі три криві проходять через нуль, краще взагалі утриматись від роботи над важливими PHP проектами. У кожної кривої власний цикл
Криві являють собою синусоїди, тому для вираховування значень біоритмів ми можемо скористатись вбудованою функцією sin() Встановлення дати народження Спочатку ми маємо отримати дату народження і вирахувати, скільки днів людина прожила до поточної дати. Результат буде використаний для вирахування поточної фази біоритму. Порядок дій
if(!isset($birthdate))
{
/* */
}
$daysGone = abs(gregorianToJD($birthMonth, $birthDay, $birthYear)
- gregorianToJD(date( "m"), date( "d"), date( "Y")));
Порада Для вираховування ми використаємо юліанський календар. Дата нвродження і поточна дата переводяться в кількість днів згідно з юліанським календарем. Різниця цих двох чисел дає результат який ми шукали. Примітка В цьому прикладі функція gregorianToJD() реалізована на PHP (див. повний код скрипта нижче). Взагалі-то ця функція реалізованав календарному модулі PHP, але на момент написання цієї статті дана функція працювала некоректно в останній версії PHP. Тому була використана "саморобна" функція. Якщо в вашому PHP включена підтримка функцій роботи з календарем, вам потрібно видалити визначення цієї функції з коду в прикладі. Підготовка зображення Порядок дій Підготовка до малювання складається з виклику декількох функцій GD. Наступна ділянка коду:
// створюємо зображення $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 значення. Порядок дій
// малюємо рамку 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($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;
}
Порада Для отримання більш плавної кривої слід було б при вираховуваннях використовувати інтервали менше одного дня, однак для цілей цієї статті отриманої якості більш ніж достатньо. Виведення зображення клієнту Отже, ми намалювали наш графік. Тепер залишається передати зображення в браузер Порядок дій
//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" border="0" />Повний код скрипта <?php
//
// Заголовок сторінки
//
function pageHeader()
{
print("<html><head>");
print("<title>Біоритми</title>");
print("</head><body>");
}
//
// Кінець сторінки
//
function pageFooter()
{
print("</body></html>");
}
//
// функція перетворення дати по григоріанському каландерю
// в юліанський календарь (кількість днів)
//
function gregorianToJD($month, $day, $year)
{
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)); ?>">
Введіть дату вашого дня народження:<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("Дата '$birthMonth/$birthDay/$birthYear' не вірна.");
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);
header("Content-type: image/png");
imageInterlace($image, 1);
imageColorTransparent($image, $colorBackgr);
imagePNG($image);
?>
ПідсумокВ даній статті розглянуті основи створення зображень в PHP з використанням функцій графічної бібліотеки GD. На доволі складному прикладі показано, як можна створювати зображення на основі введення інформації користувачем. Взявши за основу цей приклад, ви зможете створювати зображення для вирішення ваших конкретних завдань. |



PHP не лише ідеально підходить для виводу HTML сторінок, але також включає в себе потужні засоби створення зображень "на льоту". Наведу лише декілька прикладів:
Створення кнопок з написами, текст яких зберігається в базі даних
