Работа с изображениями в PHP

Автор: mike, http://www.codenet.ru/
31 января 2005 года

Эти уроки помогут вам разобраться с тем, как средствами PHP и библиотеки GD создавать разного рода изображения - счетчики, диаграммы, графики.

Я буду стараться публиковать новые уроки по понедельникам и постараюсь рассказать не только об основах, но о некоторых тонкостях, например о том как правильно узнать версию библиотеки GD, как рисовать сглаженные линии и многое другое.

  1. Урок 1 - Создание изображения
  2. Урок 2 - Рисование точки
  3. Урок 3 - Рисование линии
  4. Урок 4 - Рисование прямоугольника
  5. Урок 5 - Рисование эллипса и круга
  6. Урок 6 - Работа с полигонами
  7. Урок 7 - Заливка замкнутой области
  8. Урок 8 - Заливка сложной области
  9. Урок 9 - Построение круговой диаграммы
  10. Урок 10 - Построение гистограммы
  11. Урок 11 - Построение графика
  12. Урок 12 - Изменение размеров изображения
  13. Урок 13 - Сглаживание изображения
  14. Урок 14 - Как узнать версию библиотеки GD

Комментарии пользователей (всего 8)

Niko / 13 августа 2005, 20:41:59

Очень хорошая статья! Доходчиво и интересно.
Автору респект!

В. Пойс / 28 июля 2005, 03:17:54

Большое спасибо за статью. Вот пример четкого и ясного изложения.

XXLSoft / 25 июля 2005, 16:11:41

Спасибо за ответ mike. Думаю что развивать раздел необходимо по нескольким причинам:
1. Материал изложен очень хорошо и с примерами
2. Очень актуален, интересен
3. Да есть еще над чем поработать

Желательно продолжение данной темы не только по графике в PHP, но и задеть такие разделы как ftp, pdf, работа с файлами и т.д.

андрей / 25 июля 2005, 08:56:44

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

XXLSoft / 24 июля 2005, 14:17:58

А что дальше будет? Будет ли развитие данного раздела в последующем...

mike / 25 июля 2005, 00:11:44

<blockquote><small>Цитата:<hr size=1>А что дальше будет? Будет ли развитие данного раздела в последующем...[/quote]Посмотрим...по комментариям, по реакции на форуме.

dennp / 22 мая 2005, 15:27:45

хотелось бы поподробнее узнать о том, как грамотно можно было бы выводить текст в генерируемой картинке (PHP), причём желательно русский и с выбором шрифтов, а не так, как реализовано в GD2: только PostScript и непонятный custom'айзовый формат шрифтов

dennp / 22 мая 2005, 15:23:48

хотелось бы поподробнее узнать о том, как грамотно можно было бы выводить текст в генерируемой картинке (PHP), причём желательно русский и с выбором шрифтов, а не так, как реализовано в GD2: только PostScript и непонятный custom'айзовый формат шрифтов


Создание изображения

31 января 2005 года

Изображение создается с помощью функций imagecreate и imagecreatetruecolor.

Функция imagecreate создает изображение использующее палитру.

Каждой точке такого изображения присваивается номер цвета - от 0 до 255. Каждый цвет описывается в палитре. Таким образом изображение не может содержать более 256 цветов. В палитре каждый цвет описывается с помощью трех байт - один для красной компоненты (R), один для зеленой (G) и один для синей (B).

При использовании таких изображений целесообразно, в результате работы, генерировать GIF или PNG изображения.

Функция imagecreatetruecolor создает полноцветное изображение.

Каждая точка полноцветного изображения самостоятельно определяет свой цвет. Для хранения каждой точки используется как минимум три байта - один для красной компоненты (R), один для зеленой (G) и один для синей (B). Иногда добавляется четвертый байт. Он может быть добавлен как просто для повышения производительности, так и для определения прозрачности точки.

Такое изображение занимает больше места в памяти и в результате целесообразно генерировать JPEG или PNG изображение.

Обоим функциям передается два параметра - ширина и высота изображения. Обе функции возвращают идентификатор изображения:

Пример 1. Создание полноцветного изображения размером 320x240:

$img=imagecreatetruecolor(320,240);

Для получения результата необходимо сделать еще два действия - определить, как минимум, один цвет (в изображениях использующих палитру, первый цвет станет цветом фона) и запаковать и отправить изображение.

Выделение цветов

Для выделения цвета используется функция imagecolorallocate. В качестве параметров ей передается идентификатор изображения и три компоненты цвета (R,G и B). Значение каждой компоненты может изменятся от 0 до 255.

Пример 2. Выделение цветов

// Черный цвет
$color1=imageolorallocate($img,0,0,0);

// Белый цвет
$color2=imagecolorallocate($img,255,255,255);

// Зеленый цвет
$color3=imagecolorallocate($img,0,255,0);

Если вы привыкли задавать цвет так, как это делается в HTML, то можете использовать следующую функцию:

function htmlcolor($img,$color) {
    sscanf($color, "%2x%2x%2x", $red, $green, $blue);
    return ImageColorAllocate($img,$red,$green,$blue);
    return($c);
    }

$red=htmlcolor($img,"FF0000");

Сохранения изображения

После того, как изображение сформировано, необходимо передать его в понятном для браузера формате - GIF, JPEG или PNG. Для этого используются функции imagegif, imagejpeg и imagepng

Пример 3. Передача изображения в стандартный вывод в формате PNG

imagepng();

Если вы хотите сохранить изображение в файл, то должны передать его имя в качестве параметра функции, например:

Пример 4. Сохранение изображения в файл в формате JPEG

imagejpeg("newimage.jpg");

Примеры

Пример 5. Создания изображения, использующего палитру.

<?php
header("Content-type: image/png");
$img = imagecreate(320, 240);
$background_color = imagecolorallocate($img, 155, 255, 255);
$text_color = imagecolorallocate($img, 233, 14, 91);
imagestring($img, 2, 5, 5,  "This is example", $text_color);
imagepng($img);
imagedestroy($img);
?>

Hint: Помните! Cкрипт генерирующий изображение не может выводить никаких текстовых сообщений. Не оставляйте пустых строк перед «<?» и после«?>»

Пример 6. Создания изображения, использующего палитру.

<?php
header ("Content-type: image/png");
$img = imagecreatetruecolor(320, 240);
$text_color = imagecolorallocate($img, 233, 14, 91);
imagestring($img, 2, 5, 5,  "This is example", $text_color);
imagepng($img);
imagedestroy($img);
?>
Назад | Оглавление | Далее

Комментарии пользователей (всего 5)

kron / 12 октября 2005, 14:01:20

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

а синтаксис imagejpeg("newimage.jpg"); скорее выглядит вот так imagejpeg($img, "newimage.jpg");

kron / 12 октября 2005, 14:00:38

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

а синтаксис imagejpeg("newimage.jpg"); скорее выглядит вот так imagejpeg($img, "newimage.jpg");

Web-master / 01 февраля 2005, 13:47:48

В. Пойс, нафиг библиотеки ? если можно нарисовать и без них..т.е с помощью стардартной GD ?

В. Пойс / 01 февраля 2005, 03:37:45

Рисование графиков в PHP смотри http://www.aditus.nu/jpgraph/
Есть еще аналогичные бесплатные библиотеки.

Web-master / 31 января 2005, 18:24:11

Начальные уроки хорошо :) а вот когда будет типа рисование графиков ? :8)


Рисование точки и линии

Рисование точки

9 февраля 2005 года

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

Для рисования точки используется функция imagesetpixel:

int imagesetpixel ( resource image, int x, int y, int color)

imagesetpixel() рисует на изображении image точку с координатам x, y и цветом color. Верхний левый угол имеет координаты 0,0.

Пример 7. Рисование точки

<?php
header ("Content-type: image/png");
$img = imagecreatetruecolor(320, 240);
$ink = imagecolorallocate($img, 255, 255, 255);
imagesetpixel($img,160,120,$ink);
imagepng($img);
imagedestroy($img);
?>

Результат работы этой программы выглядит следующим образом:

С помощью точки можно нарисовать что угодно. Для иллюстрации рассмотрим такую простую программу:

Пример 8.

<?php
header ("Content-type: image/png");
$img = imagecreatetruecolor(320, 240);
for ($i=0;$i<320;$i++)
    for ($j=0;$j<240;$j++) {
        $ink = imagecolorallocate($img, $i*$j, $i*$j, $i*$j);
        imagesetpixel($img,$i,$j,$ink);
        }
imagepng($img);
imagedestroy($img);
?>

Результат работы этой программы выглядит следующим образом:

Рисование линии

Для рисования линии используется функция imageline:

int imageline ( resource image, int x1, int y1, int x2, int y2, int color)

imageline() рисует на изображении image отрезок, начинающийся в точке x1:y1, заканчивающийся в точке x2:y2 и имеющий цвет color. Верхний левый угол имеет координаты 0:0.

Пример 9. Рисование линии

<?php
header ("Content-type: image/png");
$img = imagecreatetruecolor(320, 240);
$ink = imagecolorallocate($img, 255, 255, 255);
imageline($img,0,0,320-1,240-1,$ink);
imagepng($img);
imagedestroy($img);
?>

Результат работы этой программы выглядит следующим образом:

См. также:

  • Вывод линии. алгоритм Брезенхема (PHP)
  • @Вывод линий, алгоритм Брезенхема, алгоритм ЦДА (Pascal)
  • @Вывод линии. алгоритм Брезенхема (Си)

Рисование линии произвольной ширины

Иногда появляется необходимость рисования линии произвольной толщины (пример будет рассмотрен в уроке 13). Функции рисования такой линии нет, но мы может сами написать ее:

Пример 10. Рисование линии произвольной толщины.

<?php

function imagelinethick($image, $x1, $y1, $x2, $y2, $color, $thick = 1) {
    if ($thick == 1) {
        return imageline($image, $x1, $y1, $x2, $y2, $color);
         }
    $t = $thick / 2 - 0.5;
    if ($x1 == $x2 || $y1 == $y2) {
        return imagefilledrectangle($image,
               round(min($x1, $x2) - $t),
               round(min($y1, $y2) - $t),
               round(max($x1, $x2) + $t),
               round(max($y1, $y2) + $t), $color);
         }
    $k = ($y2 - $y1) / ($x2 - $x1); //y = kx + q
    $a = $t / sqrt(1 + pow($k, 2));
    $points = array(
        round($x1 - (1+$k)*$a), round($y1 + (1-$k)*$a),
        round($x1 - (1-$k)*$a), round($y1 - (1+$k)*$a),
        round($x2 + (1+$k)*$a), round($y2 - (1-$k)*$a),
        round($x2 + (1-$k)*$a), round($y2 + (1+$k)*$a),
        );
    imagefilledpolygon($image, $points, 4, $color);
    return imagepolygon($image, $points, 4, $color);
    }

header ("Content-type: image/png");
$img = imagecreatetruecolor(320, 240);
$ink = imagecolorallocate($img, 255, 255, 255);
imagelinethick($img,10,10,320-11,240-11,$ink,2);
imagelinethick($img,10,240-10,320-11,240-(240-11),$ink,10);
imagepng($img);
imagedestroy($img);
?>

Результат работы этой программы выглядит следующим образом:

Рисование сглаженной линии

Пример рисования сглаженной линии вы можете найти здесь. Результат работы этой программы выглядит следующим образом:

На картинке хорошо видно, что линии в верхней части более гладкие. Я не рекомендую злоупотреблять функцией imagesmoothline этого примера. Она работает слишком медленно. Дождитесь лучше урока 13.

Заключение

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

  • imagecolorat - возвращает значение цвета в текущей точке.
  • imagecolorsforindex - возвращает ассоциативный массив с индексами "red", "green", "blue" и "alpha". В качестве параметра передается цвет, полученный с помощью функции imagecolorat

Пример 11. Затемнение изображения

<?php
// Коэффициент затемнения. Вычитается из каждой компоненты (R,G и B)
$DARKNESS=40;

header ("Content-type: image/png");
$img = imagecreatefromjpeg("test.jpg");

for ($i=0;$i<100;$i++)
    for ($j=0;$j<40;$j++) {
        $x=$i+530-110;
        $y=$j+10;

        $rgb = imagecolorat($img, $x, $y);
        $rgb = imagecolorsforindex($img, $rgb);

        // Если значение цвета в текущей точке больше коэффицинта затемнения
        // то просто вычитаем его. Иначе ставим в точку 0.

        $rgb["red"] = $rgb["red"] > $DARKNESS ? $rgb["red"]-$DARKNESS : 0;
        $rgb["green"] = $rgb["green"] > $DARKNESS ? $rgb["green"]-$DARKNESS : 0;
        $rgb["blue"] = $rgb["blue"] > $DARKNESS ? $rgb["blue"]-$DARKNESS : 0;

        $c=imagecolorallocate($img,$rgb["red"],$rgb["green"],$rgb["blue"]);
        imagesetpixel($img, $x, $y, $c);
        }

$white=imagecolorallocate($img,255,255,255);
imagestring($img,2,530-100,18,"www.codenet.ru",$white);
imagestring($img,2,530-100,28,"(c) 2005",$white);

imagepng($img);
imagedestroy($img);
?>

Результат работы этой программы выглядит следующим образом:

Все примеры к этому уроку можно скачать здесь.

Назад | Оглавление | Далее

Комментарии пользователей (всего 2)

Morfei / 24 февраля 2006, 13:09:18

Может примеры и хорошие, но почему ни слова про imagestring?
imagestring(resource image, int x, int y, string text, int color);

kron / 12 октября 2005, 13:45:44

Пример очень полезный но лично мне осталось не ясно как к примеру мне нарисовать процентную шкалу для опроса, ведь эта чтука считает весь документ рисунком.


Рисование прямоугольника

14 февраля 2005 года

Самый простой способ нарисовать прямоугольник - это воспользоваться функцией imagerectagle:

int imagerectangle ( resource image, int x1, int y1, int x2, int y2, int color)

Функция imagerectangle() рисует прямоугольник цвета color. Координаты верхнего левого угла прямоугольника - x1:y1, координаты нижнего правого угла прямоугольника - x2:y2. Верхний левый угол изображения имеет координаты 0:0.

Пример 12. Рисование прямоугольника:

<?
header ("Content-type: image/png");
$im = imagecreatetruecolor(320, 240);
$ink = imagecolorallocate($im, 255, 255, 255);

// Стандартный прямоугольник
imagerectangle($im,80,60,240,180,$ink);

imagepng($im);
imagedestroy($im);
?>

Результат работы этой программы выглядит следующим образом:

Рисование закрашенного прямоугольника

Для рисования закрашенного прямоугольника используется функция imagefilledrectangle:

int imagefilledrectangle ( resource image, int x1, int y1, int x2, int y2, int color)

Она рисует закрашенный прямоугольник цвета color. Координаты верхнего левого угла прямоугольника - x1:y1, координаты нижнего правого угла прямоугольника - x2:y2.

Пример 13. Рисование закрашенного прямоугольника:

<?
header ("Content-type: image/png");
$im = imagecreatetruecolor(320, 240);
$red = imagecolorallocate($im, 255, 0, 0);

// Закрашенный прямоугольник
imagefilledrectangle($im,80,60,240,180,$red);

imagepng($im);
imagedestroy($im);
?>

Результат работы этой программы выглядит следующим образом:

Рисование закрашенного прямоугольника

Проблемы при рисовании полупрозрачного прямоугольника

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

Пример 15. Рисование полупрозрачного прямоугольника:

<?php
header ("Content-type: image/png");
$im = imagecreatetruecolor(320, 240);
$ink = imagecolorallocate($im, 255, 255, 255);

$col = imagecolorallocatealpha($im, 255, 255, 255, 96);

// Функция рисующая "правильный" прямоугольник
function imagetransparentrectanle($im,$x1,$y1,$x2,$y2,$col) {
    imageline($im, $x1, $y1, $x2, $y1, $col );
    imageline($im, $x1, $y2, $x2, $y2, $col );
    imageline($im, $x1, $y1+1, $x1, $y2-1, $col );
    imageline($im, $x2, $y1+1, $x2, $y2-1, $col );
    }

// "Правильный" прямоугольник
imagetransparentrectanle($im,10,10,100,100,$col);

// Стандартный прямоугольник
imagerectangle($im,110,110,200,200,$col);

imagepng($im);
imagedestroy($im);
?>

Результат работы этой программы выглядит следующим образом:

Рисование полупрозрачного прямоугольника

«Пустой» прямоугольник

Если вы хотите нарисовать "пустой" прямоугольник, то можно воспользоваться комбинацией функций imagefilledrectangle и imagefilledrectangle. Первая функция нарисует закрашенный прямоугольник цветом фона, а вторая нарисует рамку цветом чернил.

Пример 16. Рисование "пустого" прямоугольника:

<?
header ("Content-type: image/png");
$im = imagecreatetruecolor(320, 240);
$black = imagecolorallocate($im, 0, 0, 0);
$ink = imagecolorallocate($im, 255, 255, 255);
$gray = imagecolorallocate($im, 128, 128, 128);

// Нарисуем 100 случайных линий
for ($i=0;$i<100;$i++) {
    $x1=rand(0,319);
    $x2=rand(0,319);
    $y1=rand(0,239);
    $y2=rand(0,239);
    imageline($im,$x1,$x2,$y1,$y2,$gray);
    }

// Сотрем внутреннюю часть прямоугольника
imagefilledrectangle($im,80,60,240,180,$black);

// Нарисуем рамку
imagerectangle($im,80,60,240,180,$ink);

imagepng($im);
imagedestroy($im);
?>

Результат работы этой программы выглядит следующим образом:

Рисование "пустого" прямоугольника

Прямоугольник с закругленными краями

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

Пример 17. Функция вывода прямоугольника с закругленными краями:

function ImageRectangleWithRoundedCorners(&$im, $x1, $y1, $x2, $y2, $r, $color) {
    // рисуем два прямоугольника без углов
    imagefilledrectangle($im, $x1+$r, $y1, $x2-$r, $y2, $color);
    imagefilledrectangle($im, $x1, $y1+$r, $x2, $y2-$r, $color);
    // рисуем круги в углах
    imagefilledellipse($im, $x1+$r, $y1+$r, $r*2, $r*2, $color);
    imagefilledellipse($im, $x2-$r, $y1+$r, $r*2, $r*2, $color);
    imagefilledellipse($im, $x1+$r, $y2-$r, $r*2, $r*2, $color);
    imagefilledellipse($im, $x2-$r, $y2-$r, $r*2, $r*2, $color);
    }

Результат работы этой функции выглядит следующим образом:

Рисование полупрозрачного прямоугольника

Заключение

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

Пример 18. Затемнение изображения:

<?
$DARKNESS=100;

header ("Content-type: image/png");
$img = imagecreatefromjpeg("test.jpg");
$dark = imagecolorallocatealpha($img, 0, 0, 0, $DARKNESS);
$red = imagecolorallocate($img, 255, 0, 0);
$white=imagecolorallocate($img,255,255,255);

imagefilledrectangle($img,420,15,520,45,$dark);

imagestring($img,2,530-100,18,"www.codenet.ru",$white);
imagestring($img,2,530-100,28,"(c) 2005",$white);

imagepng($img);
imagedestroy($img);
?>

Результат работы этой функции выглядит следующим образом:


Рисование эллипса и круга

Рисование эллипса

28 февраля 2005 года

Для рисования эллипса используется функция imageellipse:

int imageellipse (resource image, int cx, int cy, int w, int h, int color)

где,

  • image - идентификатор изображения;
  • cx, cy - координаты центра эллипса;
  • w - ширина эллипса (диаметр);
  • h - высота эллипса (диаметр);
  • color - цвет.

Пример 19. Рисование эллипса:

<?php
header ("Content-type: image/png");
$im = imagecreatetruecolor(320, 240);
$ink = imagecolorallocate($im, 255, 255, 255);

imageellipse($im,160,120,200,150,$ink);

imagepng($im);
imagedestroy($im);
?>

Результат работы этой программы выглядит следующим образом:

Обратите внимание: эта функция добавлена в PHP 4.0.6 и требует библиотеки GD 2.0.2

Если у вас более ранняя версия PHP (или GD), то для рисования эллипса вы можете использовать функцию imagearc:

int imagearc (resource image, int cx, int cy, int w, int h, 0, 360, int color)

где,

  • image - идентификатор изображения;
  • cx, cy - координаты центра эллипса;
  • w - ширина эллипса;
  • h - высота эллипса;
  • color - цвет.

Пример 20. Рисование эллипса с помощью функции imagearc:

<?php
header ("Content-type: image/png");
$im = imagecreatetruecolor(320, 240);
$ink = imagecolorallocate($im, 255, 255, 255);

imagearc($im,160,120,200,150,0,360,$ink);

imagepng($im);
imagedestroy($im);
?>

Результат работы этой программы выглядит следующим образом:

Рисование закрашенного эллипса

Для рисования закрашенного эллипса используется функция imagefilledellipse:

int imagefilledellipse (resource image, int cx, int cy, int w, int h, int color)

Она рисует закрашенный эллипс цвета color с центром в точке cx:cy, высотой h и шириной w пикселей.

Пример 21. Рисование закрашенного эллипса:

<?php
header ("Content-type: image/png");
$im = imagecreatetruecolor(320, 240);
$ink = imagecolorallocate($im, 255, 128, 255);

imagefilledellipse($im,160,120,200,150,$ink);

imagepng($im);
imagedestroy($im);
?>

Результат работы этой программы выглядит следующим образом:

Обратите внимание: эта функция добавлена в PHP 4.0.6 и требует библиотеки GD 2.0.2

Если у вас GD версии 2.0.1, то для рисования эллипса вы можете использовать функцию imagefilledarc:

bool imagefilledarc (resource image, int cx, int cy,
                     int w, int h, 0, 360, int color, IMG_ARC_PIE)

Пример 22. Рисование закрашенного эллипса с помощью функции imagefilledarc:

<?php
header ("Content-type: image/png");
$im = imagecreatetruecolor(320, 240);
$ink = imagecolorallocate($im, 255, 128, 255);

imagefilledarc($im,160,120,200,150,0,360,$ink,IMG_ARC_PIE);

imagepng($im);
imagedestroy($im);
?>

Результат работы этой программы выглядит следующим образом:

Обратите внимание! Эллипс нарисованный с помощью функции imagefilledarc выглядит меньше, несмотря на то что фактически имеет тот же радиус. Это отличие хорошо иллюстрирует следующий рисунок:

«Пустой» эллипс

Если вы хотите нарисовать "пустой" эллипс, то можно воспользоваться комбинацией функций imagearc и imagefilledarc. Первая функция нарисует закрашенный эллипс цветом фона, а вторая нарисует рамку цветом чернил.

Пример 23. Рисование "пустого" эллипса:

<?php
header ("Content-type: image/png");
$im = imagecreatetruecolor(320, 240);
$black = imagecolorallocate($im, 0, 0, 0);
$ink = imagecolorallocate($im, 255, 255, 255);
$gray = imagecolorallocate($im, 128, 128, 128);

// Нарисуем 100 случайных линий
for ($i=0;$i<100;$i++) {
    $x1=rand(0,319);
    $x2=rand(0,319);
    $y1=rand(0,239);
    $y2=rand(0,239);
    imageline($im,$x1,$x2,$y1,$y2,$gray);
    }

// Сотрем внутреннюю часть эллипса
imagefilledarc($im,160,120,200,150,0,360,$black,ARC_PIE);

// Нарисуем рамку
imagearc($im,160,120,200,150,0,360,$ink);

imagepng($im);
imagedestroy($im);
?>

Результат работы этой программы выглядит следующим образом:

Рисование окружности и круга

Так как круг является частным случаем эллипса, то для его рисования используются те же функции, только задаются одинаковые диаметры по высоте и ширине.

Пример 24. Вывод круга и окружности:

<?php
header ("Content-type: image/png");
$im = imagecreatetruecolor(320, 240);
$ink = imagecolorallocate($im, 255, 255, 255);
$red = imagecolorallocate($im, 255, 0, 0);

// Круг
imagefilledarc($im,110,110,100,100,0,360,$red,IMG_ARC_PIE);

// Окружность
imagearc($im,210,130,100,100,0,360,$ink);

imagepng($im);
imagedestroy($im);
?>

Результат работы этой программы выглядит следующим образом:

Смотрите также:

  • Алгоритм Брезенхема построения окружности;
  • PHP Manual - функция imagearc;
  • PHP Manual - функция imagefilledarc;
  • PHP Manual - функция imageellipse;
  • PHP Manual - функция imagefilledellipse.
Назад | Оглавление | Далее

Комментарии пользователей (всего 2)

mike / 20 апреля 2005, 09:49:54

<blockquote><small>Цитата:<hr size=1>
1. Когда же будут новые уроки? 8-)
2. Очепятка в "Примере 24. Вывод круга и окружности" в строке
imagefilledarc($im,110,110,100,100,0,360,$red,ARC_PIE);
[/quote]1. По понедельникам
2. Исправлено

WishMaster / 20 апреля 2005, 03:54:57

Респект, mike!!
1. Когда же будут новые уроки? 8-)
2. Очепятка в "Примере 24. Вывод круга и окружности" в строке
imagefilledarc($im,110,110,100,100,0,360,$red,ARC_PIE);

ARC_PIE исправить на IMG_ARC_PIE
(см. описание функции)


Работа с полигонами

8 марта 2005 года

Полигон - это абстрактная геометрическая фигура, на которой основывается вся трехмерная компьютерная графика. С греческого языка слово "полигон" переводится как многоугольник.

Для рисования полигона используется функция imagepolygon.

int imagepolygon ( resource image, array points, int num_points, int color )

где,

  • image - идентификатор изображения;
  • points - массив точек;
  • num_points - количество точек в полигоне;
  • color - цвет.

Массив точек содержит X и Y координату каждой точки. Таким образом, для трех точек, массив содержит шесть элементов: Array( X1, Y1, X2, Y2, X3, Y3)

Пример 25. Вывод самого простого полигона (треугольник):

<?php
header ("Content-type: image/png");
$im = imagecreatetruecolor(320, 240);
$ink = imagecolorallocate($im, 255, 255, 255);

imagepolygon($im, Array(
    100,100,
    120,180,
    210,160,
    ), 3, $ink);

imagepng($im);
imagedestroy($im);
?>

Результат работы этой программы выглядит следующим образом:

Полигоны очень удобно использовать при работе с векторной графикой. Я использовал полигоны для отрисовки карты мира на сайте http://r.codenet.ru/?http://top.novgorod.ru/. Файлы с контурами стран я создавал в Adobe Photoshop с помощью "Paths" и экспортировал их встроенным плагином "Export Paths to Illustrator".

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

Пример 26. Чтение файла Adobe Illustrator и вывод полигона:

<?php
// Ширина и высота изображения
$W=320;
$H=240;

// Чтения файла
$d=file("Sophia_Novgorod.ai");

// Если массив $d содержит только один элемент,
// то в качестве переноса строк используется символ
// возврата каретки, и нам необходимо разбить текст
// на строку вручную
if (count($d)==1) $d=explode("\r",$d[0]);

// С помощью регулярного выражение выберем координаты
// всех точек
$points=Array();
for ($i=0;$i<count($d);$i++)
    if (eregi("([0-9.]+) ([0-9.]+) [lm]",$d[$i],$r)) {
        $points[]=$r[1];
        $points[]=$r[2];
        }

// Найдем точки с самыми большими координатами.
// Эти значения нам понадобятся для нормализации.
$maxw=$maxh=0;
for ($i=0;$i<count($points);$i+=2) {
    if ($maxw<$points[$i]) $maxw=$points[$i];
    if ($maxh<$points[$i+1]) $maxh=$points[$i+1];
    }

// Нормализуем значения координат.
for ($i=0;$i<count($points);$i+=2) {
    $points[$i]/=$maxw;
    $points[$i+1]/=$maxh;
    }

for ($i=0;$i<count($points);$i+=2) {
    // Отмасштабируем изображение
    $points[$i]*=($W-20);
    $points[$i+1]*=($H-20);

    // Сдвинем изображение
    $points[$i]+=10;
    $points[$i+1]=$H-$points[$i+1]-10;
    }

// Создадим изображение и выделим цвета
header ("Content-type: image/png");
$im = imagecreatetruecolor($W, $H);
$ink = imagecolorallocate($im, 255, 255, 255);

// Вывод полигона
imagepolygon($im, $points, count($points)/2, $ink);

imagepng($im);
imagedestroy($im);
?>

Результат работы этой программы выглядит следующим образом:

Воспользуемся главным достоинством векторного изображения — увеличим его до 500x375, а потом и до 1024x768:

Все примеры к этому уроку можно скачать здесь.

Смотрите также:

  • PHP Manual - функция imagepolygon.


Заливка замкнутой области

21 марта 2005 года

Для заливки замкнутой области используются функции imagefill и imagefilltoborder.

Функция imagefill закрашивает все прилегающие пиксели, цвет которых совпадает с цветом начальной точки, а функция imagefilltoborder закрашивает все прилегающие пиксели, цвет которых не совпадает с цветом заданным с помощью четвертого параметра - border

int imagefill ( resource image, int x, int y, int color )

где,

  • image - идентификатор изображения;
  • x,y - координаты точки, с которой будет начата заливка;
  • color - цвет.
int imagefilltoborder ( resource image, int x, int y, int border, int color )

где,

  • image - идентификатор изображения;
  • x,y - координаты точки, с которой будет начата заливка;
  • border - цвет границы.
  • color - цвет.

Пример 27. Заливка замкнутой области с помощью функции imagefill:

<?php
header ("Content-type: image/png");

$im = imagecreatetruecolor(320, 240);
$red = imagecolorallocate($im, 255, 0, 0);
$green = imagecolorallocate($im, 0, 255, 0);
$blue = imagecolorallocate($im, 0, 0, 255);

imagerectangle($im,50,50,270,190,$blue);
imagerectangle($im,100,100,220,130,$red);

imagefill($im,160,120,$green);

imagepng($im);
imagedestroy($im);
?>

Результат работы этой программы выглядит следующим образом:

Результат работы функции imagefill

Пример 28. Заливка замкнутой области с помощью функции imagefilltoborder:

<?php
header ("Content-type: image/png");

$im = imagecreatetruecolor(320, 240);
$red = imagecolorallocate($im, 255, 0, 0);
$green = imagecolorallocate($im, 0, 255, 0);
$blue = imagecolorallocate($im, 0, 0, 255);

imagerectangle($im,50,50,270,190,$blue);
imagerectangle($im,100,100,220,130,$red);

imagefilltoborder($im,160,120,$blue,$green);

imagepng($im);
imagedestroy($im);
?>

Результат работы этой программы выглядит следующим образом:

Результат работы функции imagefilltoborder

Используйте функции imagefill и imagefilltoborder только если абсолютно уверены в том что закрашивая область замкнута. По возможности, старайтесь использовать функции imagefiledrectangle, imagefilledpolygon и imagefilledarc.

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

Ссылки по теме

  • PHP Manual - функция imagefill;
  • PHP Manual - функция imagefilltoborder;
  • PHP Manual - функция imagefilledrectangle;
  • PHP Manual - функция imagefilledarc;
  • PHP Manual - функция imagefilledpolygon.


Заливка сложной области

3 апреля 2005 года

Для заливки сложной замкнутой области удобно использовать функцию imagefilledpolygon:

int imagefilledpolygon ( resource image, array points, int num_points, int color )

где,

  • image - идентификатор изображения;
  • points - массив точек;
  • num_points - количество точек в полигоне;
  • color - цвет заливки.

Массив точек содержит X и Y координату каждой точки. Таким образом, для трех точек, массив содержит шесть элементов: Array( X1, Y1, X2, Y2, X3, Y3)

Пример 29. Вывод самого простого полигона (треугольник):

<?php
header ("Content-type: image/png");
$im = imagecreatetruecolor(320, 240);
$ink = imagecolorallocate($im, 255, 255, 255);

imagefilledpolygon($im, Array(
    100,100,
    120,180,
    210,160,
    ), 3, $ink);

imagepng($im);
imagedestroy($im);
?>

Результат работы этой программы выглядит следующим образом:

Эта функция удобна тем, что линии полигона могут пересекаться, и заливка при этом работает корректно:

Карта России

Рассмотрим следующую задачу: необходимо нарисовать карту России и выделить определенные регионы цветами, в зависимости от какого-то параметра (плотности населения, числа жителей, количества продаж и т.п.)

Задача на первый взгляд сложная, так как контуры некоторых регионов России имеют неправильную форму и использовать функцию imagefill нельзя. По этому, я использовал функцию imagepolygon для прорисовки контуров, и функцию imagefilledpolygon для закрашивания регионов.

Метод, которым я нарисовал карту рассматривался в уроке 6.

Пример 30. Рисование карты России:

<?php
// Ширина и высота изображения
$W=500;
$H=375;

// Функция выводит контуры региона и закрашивает его внутреннюю часть

// $im       - идентификатор изображения
// $filename - имя файла содержащего контур региона (в формате
//             Adobe Illustrator
// $maxw     - максимальное значение координаты X в файле с контурами
//             России (необходимо для того, чтобы все регионы
//             рисовались с одним масштабом)
// $maxh     - максимальное значение координаты Y в файле с контурами
//             России
// $color    - цвет, в который будет закрашиваться регион

function DrawIllustratorFile($im,$filename,$maxw,$maxh,$color) {
    GLOBAL $W,$H;

    // Чтения файла
    $d=file($filename);

    // Если массив $d содержит только один элемент,
    // то в качестве переноса строк используется символ
    // возврата каретки, и нам необходимо разбить текст
    // на строку вручную
    if (count($d)==1) $d=explode("\r",$d[0]);

    // С помощью регулярного выражение выберем координаты
    // всех точек.

    $poly=Array();
    for ($i=0;$i<count($d);$i++)
        if (eregi("([0-9.]+) ([0-9.]+) [lm]",$d[$i],$r)) {
            $poly[]=$r[1];
            $poly[]=$r[2];
            }

    for ($i=0;$i<count($poly);$i+=2) {
        // Нормализуем координаты
        $poly[$i]/=$maxw;
        $poly[$i+1]/=$maxh;

        // Отмасштабируем координаты
        $poly[$i]*=($W-10);
        $poly[$i+1]*=($H-10);

        // Перевернем изображение по вертикали
        $poly[$i+1]=$H-$poly[$i+1];
        }

    // Вывод полигона
    imagefilledpolygon($im, $poly, count($poly)/2, $color);
    imagepolygon($im, $poly, count($poly)/2, $color["black"]);
    }

// Чтения файла
$d=file("russia.ai");

// Если массив $d содержит только один элемент,
// то в качестве переноса строк используется символ
// возврата каретки, и нам необходимо разбить текст
// на строку вручную
if (count($d)==1) $d=explode("\r",$d[0]);

// С помощью регулярного выражение выберем координаты
// всех точек и найдем точки с самыми большими координатами.
// Эти значения нам понадобятся для нормализации.
$maxw=$maxh=0;
for ($i=0;$i<count($d);$i++)
    if (eregi("([0-9.]+) ([0-9.]+) [lm]",$d[$i],$r)) {
        if ($maxw<$r[1]) $maxw=$r[1];
        if ($maxh<$r[2]) $maxh=$r[2];
        }

// В отличи от урока 6, в одном файле может быть несколько
// полигонов. Для хранения координат их вершин, будем использовать
// двухмерный массив

// С помощью регулярного выражение выберем координаты
// всех полигонов. Формат Adobe Illustrator, прост,
// при условии использования прямых линий
$points=Array();
$num=-1;
for ($i=0;$i<count($d);$i++) {

    // Первая точка в полигоне
    if (eregi("([0-9.]+) ([0-9.]+) [m]",$d[$i],$r)) {
        $num++;
        $points[$num][]=$r[1];
        $points[$num][]=$r[2];
        }

    // Не первая точка в полигоне
    if (eregi("([0-9.]+) ([0-9.]+) [l]",$d[$i],$r)) {
        $points[$num][]=$r[1];
        $points[$num][]=$r[2];
        }
    }

// Создадим изображение и выделим цвета
header ("Content-type: image/png");
$im = imagecreatetruecolor($W, $H);
$bg = imagecolorallocate($im, 255, 255, 255);
imagefilledrectangle($im,0,0,imagesx($im),imagesy($im),$bg);

$ink=imagecolorallocate($im,0,0,0);

// Вывод полигонов
for ($j=0;$j<count($points);$j++) {

    // Перерассчитанные координаты полигона
    // будем хранить в массиве $poly
    $poly=Array();

    for ($i=0;$i<count($points[$j]);$i+=2) {
        $x=$points[$j][$i];
        $y=$points[$j][$i+1];

        // Нормализуем координаты
        $x=$x/$maxw;
        $y=$y/$maxh;

        // Отмасштабируем координаты
        $x=$x*($W-10);
        $y=$y*($H-10);

        // Перевернем изображение по вертикали
        $y=$H-$y;

        // Заносим координаты в массив, по которому
        // будет построен полигон
        $poly[]=$x;
        $poly[]=$y;
        }

    // Вывод полигона
    imagepolygon($im, $poly, count($poly)/2, $ink);
    }

// Выделим цвета для заливки регионов
$color=Array();
for ($i=196;$i<256;$i+=6) $color[]=imagecolorallocate($im,$i,$i,$i);
$color["black"]=$ink;

// Прорисовка и закрашивание регионов
DrawIllustratorFile($im,"arhangelsk.ai",$maxw,$maxh,$color[7]);
DrawIllustratorFile($im,"murmansk.ai",$maxw,$maxh,$color[5]);
DrawIllustratorFile($im,"novgorod.ai",$maxw,$maxh,$color[0]);
DrawIllustratorFile($im,"pertrozavodsk.ai",$maxw,$maxh,$color[3]);
DrawIllustratorFile($im,"pskov.ai",$maxw,$maxh,$color[8]);
DrawIllustratorFile($im,"s-petersburg.ai",$maxw,$maxh,$color[9]);
DrawIllustratorFile($im,"syktyvkar.ai",$maxw,$maxh,$color[3]);
DrawIllustratorFile($im,"vologda.ai",$maxw,$maxh,$color[4]);

imagepng($im);
imagedestroy($im);
?>

Так выглядит карта России до закрашивания регионов:

А окончательный результат работы этой программы выглядит следующим образом: (Терпения мне хватило только на обводку областей северо-западного федерального округа)

Скачать PHP скрипт рисующий карту России можно здесь.

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

Этот метод, в сочетании со сглаживанием изображения, я использовал для рисования карты мира на сайте http://top.novgorod.ru/. Вот как она выглядит:

Ссылки по теме

  • PHP Manual - функция imagefill;
  • PHP Manual - функция imagepolygon.
  • PHP Manual - функция imagefilledpolygon.


Вывод круговой диаграммы

20 апреля 2005 года

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

В этом уроке мы рассмотрим пример построения универсальной круговой диаграммы. Ее размер и размер подписи будет зависеть от размера изображения. (см. рисунки).

Круговая диаграмма строится с помощью функции imagefilledarc. В качестве 6 и 7 параметра ей передаются начальный и конечный углы сектора. Наша основная задача - рассчитать углы секторов в зависимости от передаваемых данных. Сделать это можно с помощью следующей формулы:

angle=(val/total)*360;

где,

  • angle - угол поворота грани сектора;
  • val - входное значение ;
  • total - сумма всех входных значений.

Тень у диаграммы рисуется с помощью циклического вывода диаграммы более темного цвета с изменением ее расположения по вертикали. Если вы хотите убрать тень, то можете просто исключить этот цикл из программы.

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

Рассмотрим исходный текст программы:

<?php
function Diagramm($im,$VALUES,$LEGEND) {
    GLOBAL $COLORS,$SHADOWS;

    $black=ImageColorAllocate($im,0,0,0);
  • $im - идентификатор изображения;
  • $VALUES - массив со значениями;
  • $LEGEND - массив с подписями.

Получим размеры изображения:

    $W=ImageSX($im);
    $H=ImageSY($im);

Вывод легенды

Посчитаем количество пунктов, от этого зависит высота легенды

    $legend_count=count($LEGEND);

Посчитаем максимальную длину пункта, от этого зависит ширина легенды

    $max_length=0;
    foreach($LEGEND as $v) if ($max_length<strlen($v)) $max_length=strlen($v);

Номер шрифта, котором мы будем выводить легенду. Также получим высоту и ширину символов для шрифта.

    $FONT=2;
    $font_w=ImageFontWidth($FONT);
    $font_h=ImageFontHeight($FONT);

Основные приготовления для выводе легенды закончены, теперь мы можем переходить непосредственно к рисованию. Начнем с рамки вокруг легенды. Рассчитаем ее ширину:

Ширина =

  • (ширина текста (ширина символа * максимальное количество символов)) +
  • (место для квадратика с цветом (размер квадратика равен высоте шрифта)) +
  • (отступ от левого края легенды до квадратика с цветом) +
  • (отступ от квадратика с цветом до текста) +
  • (отступ от текста для правого края легенды);
    $l_width=($font_w*$max_length)+$font_h+10+5+10;

Высота =

  • (высота текста) +
  • (отступ между текстом и верхним краем) +
  • (отступ между текстом и нижним краем)
    $l_height=$font_h*$legend_count+10+10;

Получим координаты верхнего левого угла прямоугольника - границы легенды

    $l_x1=$W-10-$l_width;
    $l_y1=($H-$l_height)/2;

Вывод прямоугольника - границы легенды

    ImageRectangle($im, $l_x1, $l_y1, $l_x1+$l_width, $l_y1+$l_height, $black);

Вывод текст легенды и цветных квадратиков

    $text_x=$l_x1+10+5+$font_h;
    $square_x=$l_x1+10;
    $y=$l_y1+10;

    $i=0;
    foreach($LEGEND as $v) {
        $dy=$y+($i*$font_h);
        ImageString($im, $FONT, $text_x, $dy, $v, $black);
        ImageFilledRectangle($im,
                             $square_x+1,$dy+1,$square_x+$font_h-1,$dy+$font_h-1,
                             $COLORS[$i]);
        ImageRectangle($im,
                       $square_x+1,$dy+1,$square_x+$font_h-1,$dy+$font_h-1,
                       $black);
        $i++;
        }

Вывод круговой диаграммы

Для начала посчитаем сумму всех значений в массиве $VALUES и инициализируем массивы. В массиве $angle будет хранится угловая ширина сектора, а в массиве $anglesum начальный угол каждого сектора. Последним элементов массива $anglesum станет его первый элемент.

    $total=array_sum($VALUES);
    $anglesum=$angle=Array(0);
    $i=1;

    // Расчет углов
    while ($i<count($VALUES)) {
        $part=$VALUES[$i-1]/$total;
        $angle[$i]=floor($part*360);
        $anglesum[$i]=array_sum($angle);
        $i++;
        }
    $anglesum[]=$anglesum[0];

Расчет диаметра

    $diametr=$l_x1-10-10;

Расчет координат центра эллипса

    $circle_x=($diametr/2)+10;
    $circle_y=$H/2-10;

Поправка диаметра, если эллипс не помещается по высоте

    if ($diametr>($H*2)-10-10) $diametr=($H*2)-20-20-40;

Вывод тени

    for ($j=20;$j>0;$j--)
        for ($i=0;$i<count($anglesum)-1;$i++)
            ImageFilledArc($im,$circle_x,$circle_y+$j,
                               $diametr,$diametr/2,
                               $anglesum[$i],$anglesum[$i+1],
                               $SHADOWS[$i],IMG_ARC_PIE);

Вывод круговой диаграммы

    for ($i=0;$i<count($anglesum)-1;$i++)
        ImageFilledArc($im,$circle_x,$circle_y,
                           $diametr,$diametr/2,
                           $anglesum[$i],$anglesum[$i+1],
                           $COLORS[$i],IMG_ARC_PIE);

    } /* Конец функции вывода круговой диаграммы */

Зададим значение и подписи

$VALUES=Array(100,200,300,400,500,400,300);
$LEGEND=Array("John","Bob","Alex","Mike","Andrew","Greg");

Создадим изображение

header("Content-Type: image/png");
$im=ImageCreate(500,500);

Зададим цвет фона. Немного желтоватый, для того, чтобы было видно границы изображения на белом фоне.

$bgcolor=ImageColorAllocate($im,255,255,200);

Зададим цвета секторов

$COLORS[0] = imagecolorallocate($im, 255, 203, 3);
$COLORS[1] = imagecolorallocate($im, 220, 101, 29);
$COLORS[2] = imagecolorallocate($im, 189, 24, 51);
$COLORS[3] = imagecolorallocate($im, 214, 0, 127);
$COLORS[4] = imagecolorallocate($im, 98, 1, 96);
$COLORS[5] = imagecolorallocate($im, 0, 62, 136);
$COLORS[6] = imagecolorallocate($im, 0, 102, 179);
$COLORS[7] = imagecolorallocate($im, 0, 145, 195);
$COLORS[8] = imagecolorallocate($im, 0, 115, 106);
$COLORS[9] = imagecolorallocate($im, 178, 210, 52);
$COLORS[10] = imagecolorallocate($im, 137, 91, 74);
$COLORS[11] = imagecolorallocate($im, 82, 56, 47);

Зададим цвета теней секторов

$SHADOWS[0] = imagecolorallocate($im, 205, 153, 0);
$SHADOWS[1] = imagecolorallocate($im, 170, 51, 0);
$SHADOWS[2] = imagecolorallocate($im, 139, 0, 1);
$SHADOWS[3] = imagecolorallocate($im, 164, 0, 77);
$SHADOWS[4] = imagecolorallocate($im, 48, 0, 46);
$SHADOWS[5] = imagecolorallocate($im, 0, 12, 86);
$SHADOWS[6] = imagecolorallocate($im, 0, 52, 129);
$SHADOWS[7] = imagecolorallocate($im, 0, 95, 145);
$SHADOWS[8] = imagecolorallocate($im, 0, 65, 56);
$SHADOWS[9] = imagecolorallocate($im, 128, 160, 2);
$SHADOWS[10] = imagecolorallocate($im, 87, 41, 24);
$SHADOWS[11] = imagecolorallocate($im, 32, 6, 0);

Вызов функции рисования диаграммы

Diagramm($im,$VALUES,$LEGEND);

Генерация изображения

ImagePNG($im)

?>

Результат работы этой программы выглядит следующим образом:

500x300

500x100

150x500

120x120

300x300

Результат работы программы для изображения 4096x2048 можно посмотреть здесь.

Пример 30: Вывод круговой диаграммы. Исходный текст с сокращенным количеством комментариев:

<?php

// $im - идентификатор изображения
// $VALUES - массив со значениями
// $LEGEND - массив с подписями
function Diagramm($im,$VALUES,$LEGEND) {
    GLOBAL $COLORS,$SHADOWS;

    $black=ImageColorAllocate($im,0,0,0);

    // Получим размеры изображения
    $W=ImageSX($im);
    $H=ImageSY($im);

    // Вывод легенды #####################################

    // Посчитаем количество пунктов, от этого зависит высота легенды
    $legend_count=count($LEGEND);

    // Посчитаем максимальную длину пункта, от этого зависит ширина легенды
    $max_length=0;
    foreach($LEGEND as $v) if ($max_length<strlen($v)) $max_length=strlen($v);

    // Номер шрифта, котором мы будем выводить легенду
    $FONT=2;
    $font_w=ImageFontWidth($FONT);
    $font_h=ImageFontHeight($FONT);

    // Вывод прямоугольника - границы легенды ----------------------------

    $l_width=($font_w*$max_length)+$font_h+10+5+10;
    $l_height=$font_h*$legend_count+10+10;

    // Получим координаты верхнего левого угла прямоугольника - границы легенды
    $l_x1=$W-10-$l_width;
    $l_y1=($H-$l_height)/2;

    // Выводя прямоугольника - границы легенды
    ImageRectangle($im, $l_x1, $l_y1, $l_x1+$l_width, $l_y1+$l_height, $black);

    // Вывод текст легенды и цветных квадратиков
    $text_x=$l_x1+10+5+$font_h;
    $square_x=$l_x1+10;
    $y=$l_y1+10;

    $i=0;
    foreach($LEGEND as $v) {
        $dy=$y+($i*$font_h);
        ImageString($im, $FONT, $text_x, $dy, $v, $black);
        ImageFilledRectangle($im,
                             $square_x+1,$dy+1,$square_x+$font_h-1,$dy+$font_h-1,
                             $COLORS[$i]);
        ImageRectangle($im,
                       $square_x+1,$dy+1,$square_x+$font_h-1,$dy+$font_h-1,
                       $black);
        $i++;
        }

    // Вывод круговой диаграммы ----------------------------------------

    $total=array_sum($VALUES);
    $anglesum=$angle=Array(0);
    $i=1;

    // Расчет углов
    while ($i<count($VALUES)) {
        $part=$VALUES[$i-1]/$total;
        $angle[$i]=floor($part*360);
        $anglesum[$i]=array_sum($angle);
        $i++;
        }
    $anglesum[]=$anglesum[0];

    // Расчет диаметра
    $diametr=$l_x1-10-10;

    // Расчет координат центра эллипса
    $circle_x=($diametr/2)+10;
    $circle_y=$H/2-10;

    // Поправка диаметра, если эллипс не помещается по высоте
    if ($diametr>($H*2)-10-10) $diametr=($H*2)-20-20-40;

    // Вывод тени
    for ($j=20;$j>0;$j--)
        for ($i=0;$i<count($anglesum)-1;$i++)
            ImageFilledArc($im,$circle_x,$circle_y+$j,
                               $diametr,$diametr/2,
                               $anglesum[$i],$anglesum[$i+1],
                               $SHADOWS[$i],IMG_ARC_PIE);

    // Вывод круговой диаграммы
    for ($i=0;$i<count($anglesum)-1;$i++)
        ImageFilledArc($im,$circle_x,$circle_y,
                           $diametr,$diametr/2,
                           $anglesum[$i],$anglesum[$i+1],
                           $COLORS[$i],IMG_ARC_PIE);
    }

// Зададим значение и подписи
$VALUES=Array(100,200,300,400,500,400,300);
$LEGEND=Array("John","Bob","Alex","Mike","Andrew","Greg");

// Создадим изображения
header("Content-Type: image/png");
$im=ImageCreate(500,500);

// Зададим цвет фона. Немного желтоватый, для того, чтобы было
// видно границы изображения на белом фоне.
$bgcolor=ImageColorAllocate($im,255,255,200);

// Зададим цвета элементов
$COLORS[0] = imagecolorallocate($im, 255, 203, 3);
$COLORS[1] = imagecolorallocate($im, 220, 101, 29);
$COLORS[2] = imagecolorallocate($im, 189, 24, 51);
$COLORS[3] = imagecolorallocate($im, 214, 0, 127);
$COLORS[4] = imagecolorallocate($im, 98, 1, 96);
$COLORS[5] = imagecolorallocate($im, 0, 62, 136);
$COLORS[6] = imagecolorallocate($im, 0, 102, 179);
$COLORS[7] = imagecolorallocate($im, 0, 145, 195);
$COLORS[8] = imagecolorallocate($im, 0, 115, 106);
$COLORS[9] = imagecolorallocate($im, 178, 210, 52);
$COLORS[10] = imagecolorallocate($im, 137, 91, 74);
$COLORS[11] = imagecolorallocate($im, 82, 56, 47);

// Зададим цвета теней элементов
$SHADOWS[0] = imagecolorallocate($im, 205, 153, 0);
$SHADOWS[1] = imagecolorallocate($im, 170, 51, 0);
$SHADOWS[2] = imagecolorallocate($im, 139, 0, 1);
$SHADOWS[3] = imagecolorallocate($im, 164, 0, 77);
$SHADOWS[4] = imagecolorallocate($im, 48, 0, 46);
$SHADOWS[5] = imagecolorallocate($im, 0, 12, 86);
$SHADOWS[6] = imagecolorallocate($im, 0, 52, 129);
$SHADOWS[7] = imagecolorallocate($im, 0, 95, 145);
$SHADOWS[8] = imagecolorallocate($im, 0, 65, 56);
$SHADOWS[9] = imagecolorallocate($im, 128, 160, 2);
$SHADOWS[10] = imagecolorallocate($im, 87, 41, 24);
$SHADOWS[11] = imagecolorallocate($im, 32, 6, 0);

// Вызов функции рисования диаграммы
Diagramm($im,$VALUES,$LEGEND);

// Генерация изображения
ImagePNG($im)
?>

Ссылки по теме

  • PHP Manual - функция imagefilledarc;
Назад | Оглавление | Далее

Комментарии пользователей (всего 4)

dbs / 16 ноября 2005, 16:16:17

статья отличная, пригодилось но нашёл ошибочку маленькую в процессе
      пользования , в куске // Расчет углов
while ($i<count($VALUES))
      {
$part=$VALUES[$i-1]/$total;
$angle[$i]=floor($part*360);
$anglesum[$i]=array_sum($angle);
$i++;
}
нужно
      do
{
$part=$VALUES[$i-1]/$total;
$angle[$i]=floor($part*360);
$anglesum[$i]=array_sum($angle);
$i++;
}
while
      ($i<count($VALUES));
потому как если count($VALUES)=1 т.е позиция
      одна и занимает 100%; ничего не нарисует, хотя автор сам наверное всё
      исправил

pps / 25 октября 2005, 22:54:00

Спасибо за урок! Автору респект. Все просто и гениально

mike / 23 апреля 2005, 16:12:10

Нужно просто потерпеть до урока №13 :)

Terri / 23 апреля 2005, 00:12:55

статья действительно отличная, ещё хотелось бы узнать как можно сделать края более сглажеными?


Вывод псевдо-объемной гистограммы

24 апреля 2005 года

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

Что такое гистограмма?

Гистограмма - (от греч. histos, здесь - столб и ...грамма), столбчатая диаграмма, один из видов графического изображения статистического распределении каких-либо величин по количественному признаку. Г. представляет собой совокупность смежных прямоугольников, построенных на прямой линии. Площадь каждого прямоугольника пропорциональна частоте нахождения данной величины в изучаемой совокупности. Пусть, например, измерение диаметров стволов 624 сосен дало следующие результаты:

Диаметр, см | 14-22 | 22-30 | 30-38 | 38-62
Число стволов | 57 | 232 | 212 | 123

Рисунок 1

Рисунок 2

На горизонтальной оси откладываются границы групп, на которые стволы разбиты по их диаметру, и на отрезке, соответствующем каждой группе, строится как на основании прямоугольник с площадью, пропорциональной числу стволов, попавших в данную группу (рис. 1).

В виде Г. часто изображают гранулометрический состав горных пород. В этом случае на вертикальной оси откладывают процентное содержание полученных групп частиц т. н. фракций, а на горизонтальной оси - логарифмы их граничных размеров (рис. 2). Использование логарифмов вызвано тем, что при гранулометрическом анализе частицы подразделяются на фракции, размеры которых убывают в геометрической прогрессии. Иногда Г. строятся на произвольно выбранных равных отрезках, независимо от разности граничных размеров фракций. Тогда высоты столбиков пропорциональны содержанию размеров фракций.

Источник: БСЭ (Большая Советская Энциклопедия)

Псевдо-объемность

Традиционная гистограмма достаточно проста в построении, по этому мы несколько усложним задачу - добавим объемность. Гистограмма, которую будет строить наша программа будет выглядеть следующим образом:

Остальные графики построенные нашей программой приведены ниже

Пример 31: Вывод круговой диаграммы. Исходный текст с сокращенным количеством комментариев:

<?
// Задаем входные данные ############################################

// Входные данные - три ряда, содержащие случайные данные.
// Деление на 2 и 3 взято для того чтобы передние ряды не
// загораживали задние.

// Массив $DATA["x"] содержит подписи по оси "X"

$DATA=Array();
for ($i=0;$i<20;$i++) {
    $DATA[0][]=rand(0,100*$i);
    $DATA[1][]=rand(0,100*$i)/2;
    $DATA[2][]=rand(0,100*$i)/3;
    $DATA["x"][]=$i;
    }

// Функция вывода псевдо-трехмерного куба ###########################

// $im - идентификатор изображения
// $x,$y - координаты верхнего левого угла куба
// $w - ширина куба
// $h - высота куба
// $dx - смещение задней грани куба по оси X
// $dy - смещение задней грани куба по оси Y
// $c1,$c2,c3 - цвета видимых граней куба

function imagebar($im,$x,$y,$w,$h,$dx,$dy,$c1,$c2,$c3) {

    if ($dx>0) {
        imagefilledpolygon($im,
            Array(
                $x, $y-$h,
                $x+$w, $y-$h,
                $x+$w+$dx, $y-$h-$dy,
                $x+$dx, $y-$dy-$h
            ), 4, $c1);

        imagefilledpolygon($im,
            Array(
                $x+$w, $y-$h,
                $x+$w, $y,
                $x+$w+$dx, $y-$dy,
                $x+$w+$dx, $y-$dy-$h
            ), 4, $c3);
        }

    imagefilledrectangle($im, $x, $y-$h, $x+$w, $y, $c2);
    }

// Задаем изменяемые значения #######################################

// Размер изображения
$W=500;
$H=300;

// Псевдо-глубина графика
$DX=30;
$DY=20;

// Отступы
$MB=20; // Нижний
$ML=10; // Левый
$M=5;   // Верхний и правый отступы. Они меньше, так как там нет текста

// Ширина одного символа
$LW=imagefontwidth(2);

// Подсчитаем количество элементов (столбиков) на графике
$count=count($DATA[0]);
if (count($DATA[1])>$count) $count=count($DATA[1]);
if (count($DATA[2])>$count) $count=count($DATA[2]);

// Подсчитаем максимальное значение
$max=0;
for ($i=0;$i<$count;$i++) {
    $max=$max<$DATA[0][$i]?$DATA[0][$i]:$max;
    $max=$max<$DATA[1][$i]?$DATA[1][$i]:$max;
    $max=$max<$DATA[2][$i]?$DATA[2][$i]:$max;
    }

// Увеличим максимальное значение на 10% (для того, чтобы столбик
// соответствующий максимальному значение не упирался в в границу
// графика
$max=intval($max+($max/10));

// Работа с изображением ############################################

// Создадим изображения
$im=imagecreate($W,$H);

// Задаем основные цвета

// Цвет фона (белый)
$bg[0]=imagecolorallocate($im,255,255,255);

// Цвет задней грани графика (светло-серый)
$bg[1]=imagecolorallocate($im,231,231,231);

// Цвет левой грани графика (серый)
$bg[2]=imagecolorallocate($im,212,212,212);

// Цвет сетки (серый, темнее)
$c=imagecolorallocate($im,184,184,184);

// Цвет текста (темно-серый)
$text=imagecolorallocate($im,136,136,136);

// Цвета для столбиков
$bar[2][0]=imagecolorallocate($im,255,128,234);
$bar[2][1]=imagecolorallocate($im,222,95,201);
$bar[2][2]=imagecolorallocate($im,191,65,170);
$bar[0][0]=imagecolorallocate($im,222,214,0);
$bar[0][1]=imagecolorallocate($im,181,187,65);
$bar[0][2]=imagecolorallocate($im,161,155,0);
$bar[1][0]=imagecolorallocate($im,128,234,255);
$bar[1][1]=imagecolorallocate($im,95,201,222);
$bar[1][2]=imagecolorallocate($im,65,170,191);

// Количество подписей и горизонтальных линий
// сетки по оси Y.
$county=10;

// Подравняем левую границу с учетом ширины подписей по оси Y
$text_width=strlen($max)*$LW;
$ML+=$text_width;

// Вывод фона графика
imageline($im, $ML, $M+$DY, $ML, $H-$MB, $c);
imageline($im, $ML, $M+$DY, $ML+$DX, $M, $c);
imageline($im, $ML, $H-$MB, $ML+$DX, $H-$MB-$DY, $c);
imageline($im, $ML, $H-$MB, $W-$M-$DX, $H-$MB, $c);
imageline($im, $W-$M-$DX, $H-$MB, $W-$M, $H-$MB-$DY, $c);

imagefilledrectangle($im, $ML+$DX, $M, $W-$M, $H-$MB-$DY, $bg[1]);
imagerectangle($im, $ML+$DX, $M, $W-$M, $H-$MB-$DY, $c);

imagefill($im, $ML+1, $H/2, $bg[2]);

// Вывод неизменяемой сетки (горизонтальные линии на
// нижней грани и вертикальные линии сетки на левой
// грани
for ($i=1;$i<3;$i++) {
    imageline($im, $ML+$i*intval($DX/3),
                   $M+$DY-$i*intval($DY/3),
                   $ML+$i*intval($DX/3),
                   $H-$MB-$i*intval($DY/3),
                   $c);
    imageline($im, $ML+$i*intval($DX/3),
                   $H-$MB-$i*intval($DY/3),
                   $W-$M-$DX+$i*intval($DX/3),
                   $H-$MB-$i*intval($DY/3),
                   $c);
    }

// Пересчитаем размеры графика с учетом подписей и отступов
$RW=$W-$ML-$M-$DX;
$RH=$H-$MB-$M-$DY;

// Координаты нулевой точки графика
$X0=$ML+$DX;
$Y0=$H-$MB-$DY;

// Вывод изменяемой сетки (вертикальные линии сетки на нижней грани графика
// и вертикальные линии на задней грани графика)
for ($i=0;$i<$count;$i++) {
    imageline($im,$X0+$i*($RW/$count),$Y0,$X0+$i*($RW/$count)-$DX,$Y0+$DY,$c);
    imageline($im,$X0+$i*($RW/$count),$Y0,$X0+$i*($RW/$count),$Y0-$RH,$c);
    }

// Горизонтальные линии сетки задней и левой граней.
$step=$RH/$county;
for ($i=0;$i<=$county;$i++) {
    imageline($im,$X0,$Y0-$step*$i,$X0+$RW,$Y0-$step*$i,$c);
    imageline($im,$X0,$Y0-$step*$i,$X0-$DX,$Y0-$step*$i+$DY,$c);
    imageline($im,$X0-$DX,$Y0-$step*$i+$DY,
                  $X0-$DX-($ML-$text_width)/4,$Y0-$step*$i+$DY,$text);
    }

// Вывод кубов для всех трех рядов
for ($i=0;$i<$count;$i++)
    imagebar($im, $X0+$i*($RW/$count)+4-1*intval($DX/3),
                  $Y0+1*intval($DY/3),
                  intval($RW/$count)-4,
                  $RH/$max*$DATA[0][$i],
                  intval($DX/3)-5,
                  intval($DY/3)-3,
                  $bar[0][0], $bar[0][1], $bar[0][2]);

for ($i=0;$i<$count;$i++)
    imagebar($im, $X0+$i*($RW/$count)+4-2*intval($DX/3),
                  $Y0+2*intval($DY/3),
                  intval($RW/$count)-4,
                  $RH/$max*$DATA[1][$i],
                  intval($DX/3)-5,
                  intval($DY/3)-3,
                  $bar[1][0], $bar[1][1], $bar[1][2]);

for ($i=0;$i<$count;$i++)
    imagebar($im, $X0+$i*($RW/$count)+4-3*intval($DX/3),
                  $Y0+3*intval($DY/3),
                  intval($RW/$count)-4,
                  $RH/$max*$DATA[2][$i],
                  intval($DX/3)-5,
                  intval($DY/3)-3,
                  $bar[2][0], $bar[2][1], $bar[2][2]);

// Вывод подписей по оси Y
for ($i=1;$i<=$county;$i++) {
    $str=intval(($max/$county)*$i);
    imagestring($im,2, $X0-$DX-strlen($str)*$LW-$ML/4-2,
                       $Y0+$DY-$step*$i-imagefontheight(2)/2,
                       $str,$text);
    }

// Вывод подписей по оси X
$prev=100000;
$twidth=$LW*strlen($DATA["x"][0])+6;
$i=$X0+$RW-$DX;

while ($i>$X0-$DX) {
    if ($prev-$twidth>$i) {
        $drawx=$i+1-($RW/$count)/2;
        if ($drawx>$X0-$DX) {
            $str=$DATA["x"][round(($i-$X0+$DX)/($RW/$count))-1];
            imageline($im,$drawx,$Y0+$DY,$i+1-($RW/$count)/2,$Y0+$DY+5,$text);
            imagestring($im,2, $drawx+1-(strlen($str)*$LW)/2 ,$Y0+$DY+7,$str,$text);
            }
        $prev=$i;
        }
    $i-=$RW/$count;
    }

header("Content-Type: image/png");

// Генерация изображения
ImagePNG($im)

imagedestroy($im);
?>

Результат работы этой программы выглядит следующим образом:

$W=500; $H=350; $DX=30; $DY=20;

$W=150; $H=150; $DX=30; $DY=20;

$W=500; $H=150; $DX=30; $DY=20;

$W=200; $H=500; $DX=30; $DY=20;

$W=300; $H=300; $DX=30; $DY=20;

$W=500; $H=300; $DX=30; $DY=120;

$W=500; $H=300; $DX=130; $DY=120;

$W=500; $H=300; $DX=130; $DY=20;

Результат работы программы для изображения 1024x768 можно посмотреть здесь.

Ссылки по теме

  • PHP Manual - функция imagefilledrectangle;
  • PHP Manual - функция imagefilledpolygon;
  • Гистограмма (БСЭ);
  • Построение круговой диаграммы.
Назад | Оглавление | Далее

Комментарии пользователей (всего 3)

DevelopeR / 26 мая 2005, 02:38:40

Не плохой скриптик, однако жаль, что не предусмотренно колличество столбцов диаграммы.
Но и это можно побороть ;)

mike / 26 апреля 2005, 16:01:54

Не всегда есть возможность таскать с собой большие библиотеки. Особенно в универсальных скриптах. (Которые распространяются, переносятся, продаются и т.п.)

Geol / 26 апреля 2005, 15:42:38

Красиво, но не лучше использовать jpgraph?
разработка сокращается в разы


Построение графика

В этом уроке мы рассмотрим пример построения графика по заданному множеству значений. Размер графика и размер подписи будет зависеть от размера изображения. (см. рисунки).

Принцип построения графиков мало отличается от принципа построения гистограммы, рассмотренного в прошлом уроке, по этому подробно мы рассматривать его не будем.

Единственное, на что стоит обратить внимание - это сглаживание. Сглаживание производится методом усреднения соседних значений. Значение каждой точки рассчитывается как средне-арифметическое пяти соседних значений:

r[x]=(v[x]+v[x-1]+v[x-2]+v[x+1]+v[x+2])/5

Для сглаживания точек в краях графика нам придется добавить по два дополнительных значения:

v[-1]=v[0];
v[-2]=v[0];
v[count+1]=v[count];
v[count+2]=v[count];

где, count - количество точек на графике

Пример 32: Построение графика.

<?
// Задаем входные данные ############################################

// Входные данные - три ряда, содержащие случайные данные.
// Деление на 2 и 3 взято для того чтобы передние ряды не
// пересекались

// Массив $DATA["x"] содержит подписи по оси "X"

$DATA=Array();
for ($i=0;$i<20;$i++) {
    $DATA[0][]=rand(0,100);
    $DATA[1][]=rand(0,100)/2;
    $DATA[2][]=rand(0,100)/3;
    $DATA["x"][]=$i;
    }

// Задаем изменяемые значения #######################################

// Размер изображения

$W=16384;
$H=8192;

// Отступы
$MB=20;  // Нижний
$ML=8;   // Левый
$M=5;    // Верхний и правый отступы.
         // Они меньше, так как там нет текста

// Ширина одного символа
$LW=imagefontwidth(2);

// Подсчитаем количество элементов (точек) на графике
$count=count($DATA[0]);
if (count($DATA[1])>$count) $count=count($DATA[1]);
if (count($DATA[2])>$count) $count=count($DATA[2]);

if ($count==0) $count=1;

// Сглаживаем графики ###############################################
if ($_GET["smooth"]==1) {

    // Добавим по две точки справа и слева от графиков. Значения в
    // этих точках примем равными крайним. Например, точка если
    // y[0]=16 и y[n]=17, то y[1]=16 и y[-2]=16 и y[n+1]=17 и y[n+2]=17

    // Такое добавление точек необходимо для сглаживания точек
    // в краях графика

    for ($j=0;$j<3;$j++) {
        $DATA[$j][-1]=$DATA[$j][-2]=$DATA[$j][0];
        $DATA[$j][$count]=$DATA[$j][$count+1]=$DATA[$j][$count-1];
        }

    // Сглаживание графики методом усреднения соседних значений

    for ($i=0;$i<$count;$i++) {
        for ($j=0;$j<3;$j++) {
            $DATA[$j][$i]=($DATA[$j][$i-1]+$DATA[$j][$i-2]+
                           $DATA[$j][$i]+$DATA[$j][$i+1]+
                           $DATA[$j][$i+2])/5;
            }
        }
    }

// Подсчитаем максимальное значение
$max=0;

for ($i=0;$i<$count;$i++) {
    $max=$max<$DATA[0][$i]?$DATA[0][$i]:$max;
    $max=$max<$DATA[1][$i]?$DATA[1][$i]:$max;
    $max=$max<$DATA[2][$i]?$DATA[2][$i]:$max;
    }

// Увеличим максимальное значение на 10% (для того, чтобы столбик
// соответствующий максимальному значение не упирался в в границу
// графика
$max=intval($max+($max/10));

// Количество подписей и горизонтальных линий
// сетки по оси Y.
$county=10;

// Работа с изображением ############################################

// Создадим изображение
$im=imagecreate($W,$H);

// Цвет фона (белый)
$bg[0]=imagecolorallocate($im,255,255,255);

// Цвет задней грани графика (светло-серый)
$bg[1]=imagecolorallocate($im,231,231,231);

// Цвет левой грани графика (серый)
$bg[2]=imagecolorallocate($im,212,212,212);

// Цвет сетки (серый, темнее)
$c=imagecolorallocate($im,184,184,184);

// Цвет текста (темно-серый)
$text=imagecolorallocate($im,136,136,136);

// Цвета для линий графиков
$bar[2]=imagecolorallocate($im,191,65,170);
$bar[0]=imagecolorallocate($im,161,155,0);
$bar[1]=imagecolorallocate($im,65,170,191);

$text_width=0;
// Вывод подписей по оси Y
for ($i=1;$i<=$county;$i++) {
    $strl=strlen(($max/$county)*$i)*$LW;
    if ($strl>$text_width) $text_width=$strl;
    }

// Подравняем левую границу с учетом ширины подписей по оси Y
$ML+=$text_width;

// Посчитаем реальные размеры графика (за вычетом подписей и
// отступов)
$RW=$W-$ML-$M;
$RH=$H-$MB-$M;

// Посчитаем координаты нуля
$X0=$ML;
$Y0=$H-$MB;

$step=$RH/$county;

// Вывод главной рамки графика
imagefilledrectangle($im, $X0, $Y0-$RH, $X0+$RW, $Y0, $bg[1]);
imagerectangle($im, $X0, $Y0, $X0+$RW, $Y0-$RH, $c);

// Вывод сетки по оси Y
for ($i=1;$i<=$county;$i++) {
    $y=$Y0-$step*$i;
    imageline($im,$X0,$y,$X0+$RW,$y,$c);
    imageline($im,$X0,$y,$X0-($ML-$text_width)/4,$y,$text);
    }

// Вывод сетки по оси X
// Вывод изменяемой сетки
for ($i=0;$i<$count;$i++) {
    imageline($im,$X0+$i*($RW/$count),$Y0,$X0+$i*($RW/$count),$Y0,$c);
    imageline($im,$X0+$i*($RW/$count),$Y0,$X0+$i*($RW/$count),$Y0-$RH,$c);
    }

// Вывод линий графика
$dx=($RW/$count)/2;

$pi=$Y0-($RH/$max*$DATA[0][0]);
$po=$Y0-($RH/$max*$DATA[1][0]);
$pu=$Y0-($RH/$max*$DATA[2][0]);
$px=intval($X0+$dx);

for ($i=1;$i<$count;$i++) {
    $x=intval($X0+$i*($RW/$count)+$dx);

    $y=$Y0-($RH/$max*$DATA[0][$i]);
    imageline($im,$px,$pi,$x,$y,$bar[0]);
    $pi=$y;

    $y=$Y0-($RH/$max*$DATA[1][$i]);
    imageline($im,$px,$po,$x,$y,$bar[1]);
    $po=$y;

    $y=$Y0-($RH/$max*$DATA[2][$i]);
    imageline($im,$px,$pu,$x,$y,$bar[2]);
    $pu=$y;
    $px=$x;
    }

// Уменьшение и пересчет координат
$ML-=$text_width;

// Вывод подписей по оси Y
for ($i=1;$i<=$county;$i++) {
    $str=($max/$county)*$i;
    imagestring($im,2, $X0-strlen($str)*$LW-$ML/4-2,$Y0-$step*$i-
                       imagefontheight(2)/2,$str,$text);
    }

// Вывод подписей по оси X
$prev=100000;
$twidth=$LW*strlen($DATA["x"][0])+6;
$i=$X0+$RW;

while ($i>$X0) {
    if ($prev-$twidth>$i) {
        $drawx=$i-($RW/$count)/2;
        if ($drawx>$X0) {
            $str=$DATA["x"][round(($i-$X0)/($RW/$count))-1];
            imageline($im,$drawx,$Y0,$i-($RW/$count)/2,$Y0+5,$text);
            imagestring($im,2, $drawx-(strlen($str)*$LW)/2, $Y0+7,$str,$text);
            }
        $prev=$i;
        }
    $i-=$RW/$count;
    }

header("Content-Type: image/png");

// Генерация изображения
ImagePNG($im);

imagedestroy($im);
?>

Результат работы этой программы выглядит следующим образом:

$W=640; $H=480;

$W=320; $H=200;

$W=140; $H=140; (минимальный размер)

$W=580; $H=140;

$W=140; $H=580;

Результат экстремального теста (для изображения 16384x8192) можно посмотреть здесь.

Ссылки по теме

  • PHP Manual - функция imagefilledrectangle;
  • PHP Manual - функция imagefilledpolygon;
  • PHP Manual - функция imagefilledline;
  • Геометрическое сглаживание В-сплайнами
  • Построение псевдо-объемной гистограммы.
  • Построение круговой диаграммы.
Назад | Оглавление | Далее

Комментарии пользователей (всего 6)

Jimmy / 10 января 2007, 14:38:16

Немного недоволен статъёй!
Я, видите ли, придирчивый слишком к аккуратности.
Кто-то скажет: "ай да подумаешь, небольшая ошибочка. Суть то ясна"
А вы представьте что данная программма используется в медицине, и от неё зависит жизнь человека....
в общем к делу.
Вот строки
// Добавим по две точки справа и слева от графиков. Значения в
// этих точках примем равными крайним. Например, точка если
// y[0]=16 и y[n]=17, то y[1]=16 и y[-2]=16 и y[n+1]=17 и y[n+2]=17

for ($j=0;$j<3;$j++) {
$DATA[$j][-1]=$DATA[$j][-2]=$DATA[$j][0];
$DATA[$j][$count]=$DATA[$j][$count+1]=$DATA[$j][$count-1];
}

Ничего не замечаете????

А вот я вижу, что предложение
// y[0]=16 и y[n]=17, то y[1]=16 и y[-2]=16 и y[n+1]=17 и y[n+2]=17
коту под хвост, только вот из за этой строчки
$DATA[$j][$count]=$DATA[$j][$count+1]=$DATA[$j][$count-1];

Или у нас в программировании поменялись правила с недавних пор????

Lander / 26 мая 2006, 10:05:53

Спасибо за информацию, вопрос такого плана, а как сделать что бы не произвольно rand а точные значения выводить? У меня есть 2 файла со значениями, первый- 10, второ1 - предположим 15, и оба они время от времени меняются, нужно что бы это отобразилось на графике! Заранее спасибо!
p.s. Я не особо силён в php, но может кто подскажет.

Yarega / 12 мая 2006, 13:23:59

не проверял, но выглядит убедительно! хороший подход к вопросам! спасибо!

Ната / 21 января 2006, 06:40:45

Классная статья, она мне очень пригодилась! Спасибо!

Вадим / 14 ноября 2005, 23:48:00

Отличная статья!

Web-master / 06 июня 2005, 11:34:33

Хорошая статья


Изменение размеров изображения

25 июня 2005 года

Как таковой, функции изменения размеров изображения в библиотеке GD нет. Есть две функции копирования части одного изображения в другое с изменением размеров копируемой части. Это функции imagecopyresized() и imagecopyresampled().

Функция imagecopyresampled() появилась в библиотеке GD с версии 2.0.1 и отличается от imagecopyresampled() тем, что при изменении размеров плавно интерполируются значения цветов в точках изображения. Это отличие хорошо иллюстрируют следующие рисунки:

Оригинал

imagecopyresize() - изображение уменьшено в три раза

imagecopyresample - изображение уменьшено в три раза()

Об ограничениях на работу функции imagecopyresampled() с палитровыми изображениями в документации по PHP ничего не сказано. Более того, там есть сноска, в которой описываются проблемы, возникающие с палитровыми изображениями. Из этого можно было бы сделать вывод, что функция работает с такими изображениями, но, просмотрев исходный код функции я убедился в обратном:

if (!dst->trueColor) {
    gdImageCopyResized (dst, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH);
    return;
}

В примерах мы будем использовать функцию imagecopyresampled(), но если у вас более старая версия GD, то просто замените "resampled" на "resized".

Пример 33: Функция изменяющая размер изображения.

<?
function imageresize($outfile,$infile,$neww,$newh,$quality) {

    $im=imagecreatefromjpeg($infile);
    $im1=imagecreatetruecolor($neww,$newh);
    imagecopyresampled($im1,$im,0,0,0,0,$neww,$newh,imagesx($im),imagesy($im));

    imagejpeg($im1,$outfile,$quality);
    imagedestroy($im);
    imagedestroy($im1);
    }

imageresize("","webcam.jpg",320,240,75);

?>

В данном примере не задано имя выходного файла. Это не ошибка. При использовании пустого имени файла, данные перенаправляются в стандартный вывод.

Пример 34: Изменение размеров изображения с заданным коэффициентом.

<?
function imageresize($outfile,$infile,$percents,$quality) {
    $im=imagecreatefromjpeg($infile);
    $w=imagesx($im)*$percents/100;
    $h=imagesy($im)*$percents/100;
    $im1=imagecreatetruecolor($w,$h);
    imagecopyresampled($im1,$im,0,0,0,0,$w,$h,imagesx($im),imagesy($im));

    imagejpeg($im1,$outfile,$quality);
    imagedestroy($im);
    imagedestroy($im1);
    }

imageresize("","webcam.jpg",30,75);

?>

Иногда необходимо вписать новое изображение в определенные рамки, например как на сервере fota.mota.ru. В таком случае можно воспользоваться следующей функцией:

Пример 35: Изменение размеров изображения с вписыванием в рамки

<?
function imageresize($outfile,$infile,$neww,$newh,$quality) {
    $im=imagecreatefromjpeg($infile);
    $k1=$neww/imagesx($im);
    $k2=$newh/imagesy($im);
    $k=$k1>$k2?$k2:$k1;

    $w=intval(imagesx($im)*$k);
    $h=intval(imagesy($im)*$k);

    $im1=imagecreatetruecolor($w,$h);
    imagecopyresampled($im1,$im,0,0,0,0,$w,$h,imagesx($im),imagesy($im));

    imagejpeg($im1,$outfile,$quality);
    imagedestroy($im);
    imagedestroy($im1);
    }

imageresize("","webcam.jpg",640,240,75);

?>

Ссылки по теме

  • PHP Manual - функция imagecopyresampled;
  • PHP Manual - функция imagecopyresized;
Назад | Оглавление | Далее

Комментарии пользователей (всего 2)

korban / 20 апреля 2006, 18:33:59

header('Content-type: image/jpeg');

function
      imageresize($outfile,$infile,$percents,$quality)
      {
$im=imagecreatefromjpeg($infile);
$w=imagesx($im)*$percents/100;
$h=imagesy($im)*$percents/100;
$im1=imagecreatetruecolor($w,$h);
imagecopyresampled($im1,$im,0,0,0,0,$w,$h,imagesx($im),imagesy($im));

imagejpeg($im1,$outfile,$quality);
imagedestroy($im);
imagedestroy($im1);
}

$d=opendir("img/user/");
while(($e=readdir($d))
      !==false) {
if (!ereg("^(.*)\.(jpg)$",$e,$P))
      continue;
$patche="img/user/$e";

$foto =
      imageresize("","$patche",75,75);
echo ("<img src='" . $foto.
      "'>"."<BR>");

}

По идее этот скрипт создает функцию
      сжатия, потом ищет все файлы JPEG и
должен вывести все фото на экран,
      но выводит только первую, остальные игнорирует! Подскажите, чего здесь не
      хватает?

Corwin Celebdil / 21 октября 2005, 10:15:47

Опечатка:

"Функция imagecopyresampled() появилась в библиотеке GD с версии 2.0.1 и отличается от imagecopyresampled() тем, что при изменении размеров <...>"

Вместо второй imagecopyresampled() должно быть imagecopyresize()


Сглаживание изображения

23 июля 2005 года

Самый простой способ сглаживания изображения - это уменьшение размера в четное количество раз с использованием фильтрации (Бикубической, Bell, B-Spline, Lanczos).

Я не удосужился разобраться, какую фильтрацию использует функция imagecopyresampled(), но судя по официальной документации PHP и проведенным мной испытаниям, она вполне подходит для наших целей.

Все что нам нужно - это построить изображение заведомо большего размера. В примере 36 я немого модифицировал исходный код примера 30 (Рисование карты России) из урока 8.

Пример 36: Сглаживание изображения с помощью двукратного уменьшения.

<?php
// Ширина и высота изображения
$W=500*2;
$H=375*2;

// Исходный код построения карты России пропущен.
// Смотрите урок №8

$imd=imagecreatetruecolor($W/2,$H/2);
imagecopyresampled($imd,$im,0,0,0,0,$W/2,$H/2,$W,$H);
imagedestroy($im);

imagepng($imd);
imagedestroy($im);
?>

Скачать исходный код в архиве (ZIP,10Kb)

Так выглядела карта до сглаживая:

Так выглядит карта после двукратного уменьшения с помощью функции imagecopyresampled():

Все гениальное просто!! Главное помните, что если вы рисуете увеличиную картинку, то на ней линии должны быть толще, текст больше и т.п.

Ссылки по теме

  • Урок 8 - Заливка сложной области ;
  • PHP Manual - функция imagecopyresampled;


Как узнать версию библиотеки GD

23 июля 2005 года

Столкнулся я в свое время с проблемой получений версии GD.

Такой вот извращенный способ получения версии библиотеки GD используется из-за того что при отсутствии GD функция gd_info() не работает, но при это функция function_exists() сообщает о том что функция существует.

Приведенный ниже код работает в PHP 4 и выше. Проверено - будет работать у всех!!

Пример 34: Получение версии библиотеки GD

<?
function gdVersion() {
    ob_start();
    phpinfo(8);
    $phpinfo=ob_get_contents();
    ob_end_clean();
    $phpinfo=stristr($phpinfo,"gd version");
    $phpinfo=stristr($phpinfo,"version");

    $end=strpos($phpinfo,"</tr>");
    if ($end) $phpinfo=substr($phpinfo,0,$end);
    $phpinfo=strip_tags($phpinfo);

    if (ereg(".*([0-9]+)\.([0-9]+)\.([0-9]+).*", $phpinfo, $r)) {
        $phpinfo=$r[1].".".$r[2].".".$r[3];
        }
    else $phpinfo=0;

    return($phpinfo);
    }

print gdVersion();
?>

Ссылки по теме

  • PHP Manual - Output Control Functions;
Назад | Оглавление | Тупик

Комментарии пользователей (всего 2)

mike / 19 января 2006, 17:00:32

<blockquote><small>Цитата:<hr size=1>В данный момент для этих целей лучше использовать функцию gd_info(), которая возвращает массив данных о библиотеке GD, включая и версию библиотеки.[/quote]В некоторых случаях такой вариант может не работать. Например при полном отсутствии библиотеки GD.

Евгений / 19 января 2006, 15:48:44

В данный момент для этих целей лучше использовать функцию gd_info(), которая возвращает массив данных о библиотеке GD, включая и версию библиотеки.