Генерация картинок на Drupal-сайте

При работе над одним своим проектом понадобилось написать 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 пикселей, белыми буквами (02FFFF) на темно-синем фоне (). Т.е. сделаем что-то вроде баннеров.

Итак, пусть модуль называется banner_generator (с полным правом, между прочим).
Реализуем в файле banner_generator.module хук меню чуть более сложный, чем выше.

function banner_generator_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>

Вернее так:

Источники

Drupal 6: index.php

Drupal 6: captcha.module

PHP: GD функции.

Второй модуль,

Второй модуль, предназначенный для генерации заголовка ноды не срабатывает. Сделал все как в примере, положил шрифт в папку модуля и кстати! переименовал функцию которая в примере:

function testimagepng_menu()

на

function banner_generator_menu()

Первый модуль (с количеством опубликованных нод) - ОК.

Поправил

Спасибо за замечание.

Отправить комментарий

Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Доступны HTML теги: <a> <em> <strong> <cite> <code> <s> <u> <ul> <ol> <li> <dl> <dt> <dd>
  • Строки и параграфы переносятся автоматически.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>. Beside the tag style "<foo>" it is also possible to use "[foo]".
  • Images can be added to this post.

Подробнее о форматировании

CAPTCHA
Защита от спама: ответьте на вопрос.
Image CAPTCHA
Enter the characters shown in the image. Ignore spaces and be careful about upper and lower case.