Генерация картинок на Drupal-сайте
Прислано: direqtor
чт, 19/06/2008 - 05:24
При работе над одним своим проектом понадобилось написать PHP-скрипт, который генерирует изображение. С PHP в этом нет ничего сложного.
Поскольку проект уже был сделан на Drupal, возникла мысль, а нельзя ли сделать это используя его возможности, например, для использования некоторых системных функций или подключения к базе данных. Оказалось можно. Причем, как минимум двумя способами: в отдельном файле и в собственном модуле.
Способ первый. Отдельный файл.
Создадим в корне сайта файл с названием image.php. Попробуем вывести изображение с числом материалов размещенных на нашем сайте.
Код очень простой:
<?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 хук меню, чтобы наше изображение получило путь на сайте.
function testimagepng_menu() { $items['testimage.png'] = array( 'type' => MENU_CALLBACK, 'page callback' => 'testimagepng_image', 'access arguments' => array('access content'), ); return $items; }
В том же файле разместим функцию testimagepng_image которая и будет генерировать изображение. Код почти совпадает с приведенным в первом способе.
function 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-изображения в виде файла:
<img src="http://example.com/testimage.png">
Изображение выглядит как статичный файл, но генерировать ее вы можете каким угодно способом внутри функции testimagepng_image().
Динамически генерируемое изображение
Небольшая неточнось, этого заголовка состоит в том, что изображение по прежнему выглядит как статичный файл, но будет генерироваться в зависимости от его названия. Попробуем запрограммировать разбор такого синтаксиса названия файла:
НОМЕР_НОДЫ-РАЗМЕР_ШРИФТА-ШИРИНА-ВЫСОТА-ЦВЕТ_ТЕКСТА-ЦВЕТ_ФОНА.РАСШИРЕНИЕ_ФАЙЛА
Например: 108-10-500-30-FFFFFF-027AC6.gif
При этом на нашем изображении формата gif будет отображаться заголовок ноды 108, шрифтом 10 пикселей, на изображении размером 500 на 30 пикселей, белыми буквами (FFFFFF) на темно-синем фоне (). Т.е. сделаем что-то вроде баннеров.
Итак, пусть модуль называется banner_generator (с полным правом, между прочим).
Реализуем в файле banner_generator.module хук меню чуть более сложный, чем выше.
function testimagepng_menu() { $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.
Реализуем требуемую функцию.
function banner_generator_generate ($file='') { /* Для отображения нелатинского текста на изображениях нам потребуется файл шрифта формата 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"); @imagepng($image); break; case 'gif': drupal_set_header("Content-type: image/gif"); @imagegif($image); break; case 'jpg': case 'jpeg': drupal_set_header("Content-type: image/jpeg"); @imagejpeg($image); break; default: imagedestroy($image); return drupal_not_found(); } /* Освобождаем ресурсы в оперативной памяти сервера и завершаем исполнение скриптов, чтобы Drupal не добавил свой вывод. */ imagedestroy($image); exit(); }
Вставлять в код сайта такое динамическое изображение можно обычным способом. Например, код баннера этой статьи будет выглядеть так:
<a href="http://shaman.asiadata.ru/node/108"><img src="http://shaman.asiadata.ru/banners/108-10---FFFFFF-027AC6.gif"></a>
Вернее так:
Источники
http://shaman.asiadata.ru/node/108
- direqtor's blog
- Для комментирования войдите или зарегистрируйтесь
Пригодится, спасибо.
- Для комментирования войдите или зарегистрируйтесь
Отличная работа. Очень понятно написано. Спасибо. Даже не знал, что можно так просто это сделать!
- Для комментирования войдите или зарегистрируйтесь
Супер. Очень просто и оригинально.
- Для комментирования войдите или зарегистрируйтесь
Меня со вчерашнего дня терзали смутные сомнения, что должно быть просто.
Оказалось так и есть... :)
- Для комментирования войдите или зарегистрируйтесь
Очень интересно. Скажите, а нельзя ли подобным образом выделять в постах заглавные литеры?
- Для комментирования войдите или зарегистрируйтесь
Заменять первую букву в посте на картинку? Пишем свой фильтр, заменяющий первую букву на ссылку на картинку. Сами картинки проще один раз сгенерировать, чем каждый раз. Или можно обертывать первую букву в стиль, а при помощи jquery заменить его на картинку.
Есть ещё техника, позволяющая заменить выделенный классом текст на флеш, в котором текст будет написан заранее внедренным шрифтом, sIFR называется.
- Для комментирования войдите или зарегистрируйтесь
Но лучше всего использовать возможности CSS
- Для комментирования войдите или зарегистрируйтесь
Коротко и ясно! Спасибо.
- Для комментирования войдите или зарегистрируйтесь
Интересно, спасибо. Но... в плане практического применения, идей нет. А что думает народ?
- Для комментирования войдите или зарегистрируйтесь
Можно строить какие-нибудь графики, чарты. Например, карму выстраивать.
- Для комментирования войдите или зарегистрируйтесь
Насчёт применения. Я думаю, что так стоит выводить только динамический контент (Капча?), который нельзя вывести текстом на фоне картинки.
Решение было сохранено на сайте DrupalCookBook.ru:
Генерация картинок на Drupal-сайте.
Авторы, предложившие решения, также указаны в сохранённой статье.
- Для комментирования войдите или зарегистрируйтесь
С графиками отличная идея, надо подумать...
- Для комментирования войдите или зарегистрируйтесь
Я старую свою програмку для транскрипции имен на китайский собираюсь так переделать.
- Для комментирования войдите или зарегистрируйтесь
Трабла первого варианта в том, что этот файл никуда не положить, кроме как в корень проекта.
- Для комментирования войдите или зарегистрируйтесь
очень большая разница между отработчиком меню для AJAX и для вывода картинки, да. очень.
в Content-type :)
Мы такое уже давно делали.
- Для комментирования войдите или зарегистрируйтесь
Интересно, спасибо. Но... в плане практического применения, идей нет. А что думает народ?
Недавно нечто похожее делал для защиты изображений от не авторизованных пользователей
- Для комментирования войдите или зарегистрируйтесь
По результатам своей работы за прошлую неделю серьезно проапгрейдил статью. Дописал еще один модуль для динамических изображений.
- Для комментирования войдите или зарегистрируйтесь
cool
- Для комментирования войдите или зарегистрируйтесь
Столько времени прошло, а пригодилось, спасибо.
- Для комментирования войдите или зарегистрируйтесь
Йо майо ... как раз бубунец напрягал как друпалом это сделать. Спасибо!
- Для комментирования войдите или зарегистрируйтесь
блин, руки кривые (((
первый вариант с php получился, но надо png
никак не могу сделать модуль!!!
вроде и папку создавал, и файл туды клал ... никак (((
- Для комментирования войдите или зарегистрируйтесь
блин, руки кривые (((
первый вариант с php получился, но надо png
никак не могу сделать модуль!!!
вроде и папку создавал, и файл туды клал ... никак (((
- Для комментирования войдите или зарегистрируйтесь
разобрался: надо создать testimagepng.info
я взял .info с workspace
и вставил в testimagepng.info
; $Id: testimagepng.info,v 1.3 2008/05/02 21:55:04 jvandyk Exp $ 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р
после чего заработало )
- Для комментирования войдите или зарегистрируйтесь












Комментарии