При работе над одним своим проектом понадобилось написать PHP-скрипт, который генерирует изображение. С PHP в этом нет ничего сложного.
Поскольку проект уже был сделан на Drupal, возникла мысль, а нельзя ли сделать это используя его возможности, например, для использования некоторых системных функций или подключения к базе данных. Оказалось можно. Причем, как минимум двумя способами: в отдельном файле и в собственном модуле.
Способ первый. Отдельный файл.
Создадим в корне сайта файл с названием image.php. Попробуем вывести изображение с числом материалов размещенных на нашем сайте.
Код очень простой:
/*
Подключаем Drupal и загружаем его.
После вызова функции drupal_bootstrap доступны все функции
и системные переменные Drupal.
*/
require_once './includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
/*
Отправляем браузеру заголовок типа контента: изображение в формате PNG.
*/
drupal_set_header("Content-type: image/png");
/*
Создаем изображение.
*/
$image = imagecreate(88, 31);
/*
Определяем цвета фона и текста.
*/
$background_color = imagecolorallocate($image, 2, 122, 198);
$text_color = imagecolorallocate($image, 255, 255, 255);
/*
Заливаем фон изображения.
*/
imagefill($image, 0, 0, $background_color);
/*
Запрашиваем из таблицы нод количество материалов сайта.
*/
$query = "SELECT COUNT(`nid`) FROM `{node}`";
$result = db_result(db_query ($query));
/*
Выводим результат в изображение.
*/
imagestring($image, 5, 5, 7, $result , $text_color);
/*
Отдаем изображение в браузер.
*/
imagepng($image);
/*
Освобождаем ресурсы в оперативной памяти сервера.
*/
imagedestroy($image);
Способ второй. Модуль Drupal.
Статичное изображение
Пусть наш модуль называется testimagepng.
Реализуем в файле testimagepng.module хук меню, чтобы наше изображение получило путь на сайте.
$items['testimage.png'] = array(
'type' => MENU_CALLBACK,
'page callback' => 'testimagepng_image',
'access arguments' => array('access content'),
);
return $items;
}
В том же файле разместим функцию testimagepng_image которая и будет генерировать изображение. Код почти совпадает с приведенным в первом способе.
drupal_set_header("Content-type: image/png");
$image = imagecreate(88, 31);
$background_color = imagecolorallocate($image, 2, 122, 198);
$text_color = imagecolorallocate($image, 255, 255, 255);
imagefill($image, 0, 0, $background_color);
$query = "SELECT COUNT(`nid`) FROM `{node}`";
$result = db_result(db_query ($query));
imagestring($image, 5, 5, 7, $result , $text_color);
imagepng($image);
imagedestroy($image);
/*
Прерываем выполнение скриптов, чтобы Drupal не посылал в конце изображения своего вывода.
*/
exit();
}
Достоинством этого метода генерации картинок состоит в том, что в HTML она вставляется при помощи кода, который ничем не отличается от кода для вставки обычного PNG-изображения в виде файла:
Изображение выглядит как статичный файл, но генерировать ее вы можете каким угодно способом внутри функции testimagepng_image().
Динамически генерируемое изображение
Небольшая неточнось, этого заголовка состоит в том, что изображение по прежнему выглядит как статичный файл, но будет генерироваться в зависимости от его названия. Попробуем запрограммировать разбор такого синтаксиса названия файла:
НОМЕР_НОДЫ-РАЗМЕР_ШРИФТА-ШИРИНА-ВЫСОТА-ЦВЕТ_ТЕКСТА-ЦВЕТ_ФОНА.РАСШИРЕНИЕ_ФАЙЛА
Например: 108-10-500-30-FFFFFF-027AC6.gif
При этом на нашем изображении формата gif будет отображаться заголовок ноды 108, шрифтом 10 пикселей, на изображении размером 500 на 30 пикселей, белыми буквами (FFFFFF) на темно-синем фоне (). Т.е. сделаем что-то вроде баннеров.
Итак, пусть модуль называется banner_generator (с полным правом, между прочим).
Реализуем в файле banner_generator.module хук меню чуть более сложный, чем выше.
$items['banners/%'] = array(
'page arguments' => array(1),
'type' => MENU_CALLBACK,
'page callback' => 'banner_generator_generate',
'access arguments' => array('access content'),
);
return $items;
}
После включения модуля в структуре нашего сайта появится адрес http://example.com/banners/ приобращении к которому все, что мы наберем после завершающего слеша попадет в функцию banner_generator_generate () в качестве первого параметра. Т.е., если мы запросим адрес http://example.com/banners/108-10-500-30-FFFFFF-027AC6.gif, то функции будет передан аргумент 108-10-500-30-FFFFFF-027AC6.gif.
Реализуем требуемую функцию.
/*
Для отображения нелатинского текста на изображениях нам потребуется файл шрифта формата True Type
Файл должен лежать в папке модуля. Взять его можно из папки шрифтов Windows.
Ф случае отсутствия файла Drupal сгенерирует страницу Page not found.
*/
$font = drupal_get_path('module', 'banner_generator') . "/arial.ttf";
if (!file_exists($font)) return drupal_not_found();
/*
Разбиваем полученый параметр на имя файла и расширение.
*/
$tmp = explode('.', $file);
$name = array_shift($tmp);
$ext = strtolower(array_pop($tmp));
/*
Разбиваем по дефисам имя файла на отдельные компоненты.
*/
$tmp = explode('-', $name);
/*
Получаем идентификатор ноды и достаем заголовок нужной страницы из базы.
*/
$nid = (int) array_shift($tmp);
$query = "SELECT `title` FROM `{node}` WHERE `nid`=%d";
$result = db_result(db_query ($query, $nid));
if ($result===FALSE) return drupal_not_found();
/*
Получаем размер шрифта. В случае, слишком большого, неправильного
или отсутствующего значения ставим по умолчанию в 15px.
*/
$size = (int) array_shift($tmp);
$size = $size < 1 ? 15 : $size;
$size = $size > 100 ? 15 : $size;
/*
Определяем размеры контейнера требуемого для текста.
*/
list($lower_left_X, $lower_left_Y, $lower_right_X, $lower_right_Y, $upper_right_X, $upper_right_Y, $upper_left_X, $upper_left_Y) = imagettfbbox ($size, 0, $font, $result);
$box_width = max($lower_left_X, $lower_right_X, $upper_right_X, $upper_left_X) - min ($lower_left_X, $lower_right_X, $upper_right_X, $upper_left_X) + 1;
$box_height = max($lower_left_Y, $lower_right_Y, $upper_right_Y, $upper_left_Y) - min($lower_left_Y, $lower_right_Y, $upper_right_Y, $upper_left_Y) + 1;
/*
Теперь получаем требуемую ширину изображения. Если она отсутствует, слишком мала или велика,
то устанавливаем ее чуть больше контейнера текста
*/
$width = (int) array_shift($tmp);
$width = $width <1 ? $box_width + $size : $width;
$width = $width > 1000 ? $box_width + $size : $width;
$height = (int) array_shift($tmp);
$height = $height <1 ? $box_height + $size : $height;
$height = $height > 1000 ? $box_height + $size : $height;
/*
Создаем изображение рассчитанных размеров
*/
$image = imagecreatetruecolor($width, $height);
if (!$image) return drupal_not_found();
/*
Получаем и задаем для изображения цвет текста и разбираем его на
красный, зеленый и голубой цвета. Все ошибки трактуются в пользу отсутствия цвета.
*/
$color = array_shift($tmp);
$red = substr($color, 0, 2);
$red = $red ? $red : '00';
$green = substr($color, 2, 2);
$green = $green ? $green : '00';
$blue = substr($color, 4, 2);
$blue = $blue ? $blue : '00';
$text_color = imagecolorallocate($image, hexdec($red), hexdec($green), hexdec($blue));
/*
Получаем и задаем для изображения цвет фона и разбираем его на
красный, зеленый и голубой цвета. Все ошибки трактуются в пользу наличия цвета.
Заливаем фон.
*/
$color = array_shift($tmp);
$red = substr($color, 0, 2);
$red = $red ? $red : 'FF';
$green = substr($color, 2, 2);
$green = $green ? $green : 'FF';
$blue = substr($color, 4, 2);
$blue = $blue ? $blue : 'FF';
$background_color = imagecolorallocate($image, hexdec($red), hexdec($green), hexdec($blue));
imagefill($image, 0, 0, $background_color);
/*
Рассчитываем координаты левого нижнего угла контейнера текста
(это особенность функции imagettftext) так, чтобы контейнер встал
по центру изображения. После этого выводим текст в изображение.
*/
$x = (int) ($width - $box_width)/2;
$y = (int) ($height + $box_height - $size/2)/2;
imagettftext ($image, $size, 0, $x, $y, $text_color, $font, $result);
/*
Теперь в зависимости от расширения файла посылаем браузеру клиента соответствующие заголовкии
и отдаем изображение. В случае неправильного расширения генерируем ошибку Page not found.
*/
switch ($ext) {
case 'png':
drupal_set_header("Content-type: image/png");
[user=imagepng]imagepng[/user]($image);
break;
case 'gif':
drupal_set_header("Content-type: image/gif");
[user=imagegif]imagegif[/user]($image);
break;
case 'jpg':
case 'jpeg':
drupal_set_header("Content-type: image/jpeg");
[user=imagejpeg]imagejpeg[/user]($image);
break;
default:
imagedestroy($image);
return drupal_not_found();
}
/*
Освобождаем ресурсы в оперативной памяти сервера и завершаем исполнение скриптов,
чтобы Drupal не добавил свой вывод.
*/
imagedestroy($image);
exit();
}
Вставлять в код сайта такое динамическое изображение можно обычным способом. Например, код баннера этой статьи будет выглядеть так:
Вернее так:
Комментарии
Пригодится, спасибо.
Отличная работа. Очень понятно написано. Спасибо. Даже не знал, что можно так просто это сделать!
Меня со вчерашнего дня терзали смутные сомнения, что должно быть просто.![Smile](https://drupal.ru/sites/all/modules/contrib/smiley/packs/kolobok/smile.gif)
Оказалось так и есть...
очень большая разница между отработчиком меню для AJAX и для вывода картинки, да. очень.
в Content-type![Smile](https://drupal.ru/sites/all/modules/contrib/smiley/packs/kolobok/smile.gif)
Мы такое уже давно делали.
Супер. Очень просто и оригинально.
Очень интересно. Скажите, а нельзя ли подобным образом выделять в постах заглавные литеры?
[deleted]
Но лучше всего использовать возможности CSS
Коротко и ясно! Спасибо.
Интересно, спасибо. Но... в плане практического применения, идей нет. А что думает народ?
Недавно нечто похожее делал для защиты изображений от не авторизованных пользователей
Можно строить какие-нибудь графики, чарты. Например, карму выстраивать.
Насчёт применения. Я думаю, что так стоит выводить только динамический контент (Капча?), который нельзя вывести текстом на фоне картинки.
Генерация картинок на Drupal-сайте.
Авторы, предложившие решения, также указаны в сохранённой статье.
С графиками отличная идея, надо подумать...
Я старую свою програмку для транскрипции имен на китайский собираюсь так переделать.
Трабла первого варианта в том, что этот файл никуда не положить, кроме как в корень проекта.
По результатам своей работы за прошлую неделю серьезно проапгрейдил статью. Дописал еще один модуль для динамических изображений.
cool
Столько времени прошло, а пригодилось, спасибо.
Йо майо ... как раз бубунец напрягал как друпалом это сделать. Спасибо!
блин, руки кривые (((
первый вариант с php получился, но надо png
никак не могу сделать модуль!!!
вроде и папку создавал, и файл туды клал ... никак (((
блин, руки кривые (((
первый вариант с php получился, но надо png
никак не могу сделать модуль!!!
вроде и папку создавал, и файл туды клал ... никак (((
разобрался: надо создать testimagepng.info
я взял .info с workspace
и вставил в testimagepng.info
name = testimagepng
description = testimagepng.
core = 6.x
; Information added by drupal.org packaging script on 2008-07-24
version = "6.x-1.3"
core = "6.x"
project = "testimagepng"
datestamp = "1216932917"
в testimagepng.module надо в начало вставить <?рhр
после чего заработало )
Огромное спасибо!! Очень полезный пост.
Пример заработал даже под 7
Да не за что. Я уже и забыл про эту статью.![Smile](https://drupal.ru/sites/all/modules/contrib/smiley/packs/kolobok/smile.gif)