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

Главные вкладки

Аватар пользователя direqtor direqtor 19 июня 2008 в 9: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-изображения в виде файла:

Изображение выглядит как статичный файл, но генерировать ее вы можете каким угодно способом внутри функции 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");
          [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();
}

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

Вернее так:

Источники

Drupal 6: index.php

Drupal 6: captcha.module

PHP: GD функции.

http://shaman.asiadata.ru/node/108

Комментарии

Аватар пользователя MichaelMV MichaelMV 24 июня 2008 в 17:53

Resistant wrote:
Интересно, спасибо. Но... в плане практического применения, идей нет. А что думает народ?

Недавно нечто похожее делал для защиты изображений от не авторизованных пользователей

Аватар пользователя VladSavitsky VladSavitsky 19 июня 2008 в 18:26

Насчёт применения. Я думаю, что так стоит выводить только динамический контент (Капча?), который нельзя вывести текстом на фоне картинки.

Drupal CookBook - Готовить может каждый!Решение было сохранено на сайте DrupalCookBook.ru:

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

Авторы, предложившие решения, также указаны в сохранённой статье.

Аватар пользователя direqtor direqtor 30 июня 2008 в 6:59

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

Аватар пользователя sqdimon sqdimon 8 декабря 2011 в 6:05

блин, руки кривые (((
первый вариант с php получился, но надо png
никак не могу сделать модуль!!!
вроде и папку создавал, и файл туды клал ... никак (((

Аватар пользователя sqdimon sqdimon 8 декабря 2011 в 6:05

блин, руки кривые (((
первый вариант с php получился, но надо png
никак не могу сделать модуль!!!
вроде и папку создавал, и файл туды клал ... никак (((

Аватар пользователя sqdimon sqdimon 8 декабря 2011 в 6:21

разобрался: надо создать 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р
после чего заработало )