PHP - закругление углов у картинки

Давно было интересно как можно в PHP сделать с картинкой что-нибудь такое как указано в заголовке, а тут ещё и задание соответствующее попалось.

Для выполнения задания необходимо было обойтись по возможности штатными средствами PHP, потому что установка чего-то дополнительного — это отдельный процесс. Поэтому я стал искать решения в модуле GD.

Если вам, также как и мне, интересно что значит «GD», то вот ответ:

В GD 1.0, это означало «gif draw». После того как Unisys запатентовало алгоритм LZW сжатия, используемый в GIF и поддержка GIF была убрана, аббревиатура оффицально ничего не обознает, поэтому пусть просто будет «graphics draw» и всё. (поддержка GIF возвращена, благодаря тому что срок действия патента истёк, но GD может гораздо больше чем создание GIF)

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

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

Поэтому последовательность действий у меня следующая:

на временной картинке рисую те части, которые должны стать прозрачными в результате;

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

imagesavealpha($img_res, true);

, а вот наличие альфа канала у временного изображения не важно (я использовал true color, потому что в этом случае на один вызов функции imagecolortransparent() меньше).

Решение:
class ImgUtils
{
    public static function imageToRes($img_file)
    {
        $img_res = false;
 
        list($tmp, $tmp, $type) = getimagesize($img_file);
 
        switch ($type)
        {
            case 2: // JPEG
 
                $img_res = imagecreatefromjpeg($img_file);
                break;
 
            case 1: // GIF
 
                $img_res = imagecreatefromgif($img_file);
                break;
 
            case 3: // PNG
 
                $img_res = imagecreatefrompng($img_file);
                break;
        }
 
        return $img_res;
    }
 
 
    public static function roundedCorners($img_res, $radius)
    {
        $width  = imagesx($img_res);
        $height = imagesy($img_res);
 
        imagesavealpha($img_res, true);
 
        // corners START
        $img_tmp = imagecreate($width, $height);
 
        $black  = imagecolorallocate($img_tmp, 0, 0, 0);
        $transp = imagecolorallocatealpha($img_tmp,
                                            0, 0, 0, 127);
 
        imagefill($img_tmp, $width / 2, $height / 2, $transp);
 
        // left upper
        imagearc($img_tmp,  $radius / 2 - 1,
                            $radius / 2 - 1,
                            $radius,
                            $radius, 180, 270, $black);
        imagefill($img_tmp, 0, 0, $black);
        // right upper
        imagearc($img_tmp,  $width - $radius / 2,
                            $radius / 2 - 1,
                            $radius,
                            $radius, 270, 0, $black);
        imagefill($img_tmp, $width - 1, 0, $black);
        // right lower
        imagearc($img_tmp,  $width - $radius / 2,
                            $height - $radius / 2,
                            $radius,
                            $radius, 0, 90, $black);
        imagefill($img_tmp, $width - 1, $height - 1, $black);
        // left lower
        imagearc($img_tmp,  $radius / 2 - 1,
                            $height - $radius / 2,
                            $radius,
                            $radius, 90, 180, $black);
        imagefill($img_tmp, 0, $height - 1, $black);
 
        // corners END
 
        imagecopyresampled($img_res, $img_tmp,
                            0, 0, 0, 0,
                            $width, $height, $width, $height);
 
        $transp = imagecolorallocatealpha($img_res,
                                            0, 0, 0, 127);
        imagefill($img_res, 0, 0, $transp);
        imagefill($img_res, $width - 1, 0, $transp);
        imagefill($img_res, $width - 1, $height - 1, $transp);
        imagefill($img_res, 0, $height - 1, $transp);
 
        imagedestroy($img_tmp);
 
        return $img_res;
    }
}

Изначально я пытался нарисовать «уголки» на временном изображении при помощи одного прямоугольника и одного эллипса наложенного поверх. Оказалось что в таких условиях трудно контролировать радиус углов — тогда я стал рисовать на каждый угол по своей окружности.

Добавлено: 31 Марта 2021 19:21:11 Добавил: Андрей Ковальчук

Загрузка картинок на ImageShack.us

Код загружает файл image.jpg, находящийся в одной директории со скриптом, на сервер ImageShack.us, и выводит прямую ссылку на загруженное изображение:

$filename = dirname(__FILE__) . '/image.jpg';
 
$postData = array(
    'fileupload' => '@' . $filename,
    'key'        => '*********', // ключ полученный на странице http://stream.imageshack.us/xmlapi/
    'xml'        => 'yes',
);
 
$ch = curl_init('http://www.imageshack.us/upload_api.php');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
$result = curl_exec($ch);
curl_close($ch);
 
$xml = simplexml_load_string($result);
 
if (!$xml)
{
    echo 'Error';
}
else if (isset($xml->error))
{
    echo 'Error: ' . $xml->error;
}
else
{
    echo 'Image URL: ' . $xml->links->image_link;
}

Добавлено: 26 Июля 2018 20:11:26 Добавил: Андрей Ковальчук

Скачать картинку по её url

Первый вариант будет работать если в php.ini, параметр allow_url_fopen равен 1:

$url = 'http://img.yandex.net/i/www/logo.png';
$path = './images/logo.png';
file_put_contents($path, file_get_contents($url));

Второй вариант использует cURL:

$ch = curl_init('http://img.yandex.net/i/www/logo.png');
$fp = fopen('./images/logo.png', 'wb');
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
fclose($fp);

Добавлено: 26 Июля 2018 19:22:48 Добавил: Андрей Ковальчук

Программа: создание гистограмм результатов голосования

Показ результатов голосования может быть более наглядным при использовании красочной гистограммы, вместо простой распечатки результатов в виде текста. Функция, представленная в примере 15.4, использует библиотеку GD для создания изображения, которое показывает совокупные ответы на вопрос, поставленный на голосование.

Пример 15.4. Графические гистограммы

Function pc_bar_chart($question, $answers) {
// определяем цвета для рисования полос
$colors = array(array(255,102,0), array(0,153,0),
array(51,51,204), array(255,0,51),
array(255,255,0), array(102,255,255),
array(153,0,204));
$total = array_sum($answers['votes']);
// определяем значения для промежутков и других магических чисел
$padding = 5;
$line_width = 20;
$scale = $line_width * 7.5;
$bar_height = 10;
$x = $y = $padding;// размещаем большую палитру для рисования, поскольку мы не знаем
// заранее длину изображения
$image = ImageCreate(150, 500);
$bg_color = ImageColorAllocate($image, 224, 224, 224);
$black = ImageColorAllocate($image, 0, 0, 0);
// печатаем вопрос
$wrapped = explode("\n", wordwrap($question, $line_width));
foreach ($wrapped as $line) {
ImageString($image, 3, $x, $y , $line, $black);
$y += 12;
}
$y += $padding;
// печатаем ответы
for ($i = 0; $i < count($answers['answer']); $i++) {
// формируем процентное соотношение
$percent = sprintf('%1.1f', 100*$answers['votes'][$i]/$total);
$bar = sprintf('%d', $scale*$answers['votes'][$i]/$total);
// выбираем цвет
$c = $i % count($colors); // обрабатываем случаи с большим
количеством полос, чем цветов
$text_color = ImageColorAllocate($image, $colors[$c][0],
$colors[$c], $colors[$c]);
// рисуем полосу и числа с процентами
ImageFilledRectangle($image, $x, $y, $x + $bar,
$y + $bar_height, $text_color);
ImageString($image, 3, $x + $bar + $padding, $y,
"$percent%", $black);
$y += 12;
// печатаем ответ
$wrapped = explode("\n", wordwrap($answers['answer'][$i],
$line_width));
foreach ($wrapped as $line) {
ImageString($image, 2, $x, $y, $line, $black);
$y += 12;
}
$y += 7;
}
// обрезаем изображение с помощью его копирования
$chart = ImageCreate(150, $y);
ImageCopy($chart, $image, 0, 0, 0, 0, 150, $y);
// доставляем изображение
header ('Content-type: image/png');
ImagePNG($chart);
// удаляем
ImageDestroy($image);ImageDestroy($chart);
}


Для вызова этой программы создайте массив, содержащий два параллельных массива: $answers['answer'] и $answer['votes']. Элемент $i каждого массива хранит текст ответа и общее количество голосов, поданных за ответ $i.

// Акт II. Сцена II.
$question = 'What a piece of work is man?';
$answers['answer'][] = 'Noble in reason';
$answers['votes'][] = 29;
$answers['answer'][] = 'Infinite in faculty';
$answers['votes'][] = 22;
$answers['answer'][] = 'In form, in moving, how express and admirable';
$answers['votes'][] = 59;
$answers['answer'][] = 'In action how like an angel';
$answers['votes'][] = 45;
pc_bar_chart($question, $answers);


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

Эта программа представляет собой хорошее начало, но поскольку она использует встроенные в GD шрифты, здесь имеется большое количество внедренных в программу магических чисел, соответствующих высоте и ширине шрифтов. Кроме того, пространственные промежутки между ответами жестко зашиты в программе. Если вы модифицируете программу для использования более продвинутых шрифтов, таких как PostScript или TrueType, то вам придется обновить алгоритм, управляющий этими числами.
В начале функции определяется группа комбинаций RGB; они используются в качестве цветов для рисования полос. Объявлено множествоконстант, например: $line_width представляет максимальное количество символов в строке, переменная $bar_height определяет высоту полос, а $scale определяет масштаб длины полосы как функцию от самой длинной строки. Переменная $padding нужна для того, чтобы отодвинуть результаты на пять пикселов от границы области отображения.

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

Для того чтобы разумно ограничить ширину диаграммы, мы используем функцию wordwrap() для разбиения переменной $question на строки меньшего размера и ограничиваем их символом \n с помощью функции explode(). Это дает нам массив строк с правильными размерами, которые мы будем печатать в цикле по одной строке за раз.

Напечатав вопрос, переходим к ответам. Во-первых, форматируем числа результатов с помощью функции sprintf(). Чтобы отформатировать общий процент голосов, поданных за определенный ответ, в виде числа с плавающей точкой и одним десятичным разрядом, указываем формат %1.1f. Для определения длины полосы, соответствующей этому числу, задаем подобное число, но умножаем его не на 100, а на магическое число $scale, а затем возвращаем целое значение.

Цвет текста извлекается из массива $colors, содержащего RGB-тройки. Затем мы вызываем функцию ImageFilledRectangle() для рисования полосы и функцию ImageString() для рисования текста с процентами справа от полосы. После закрашивания мы печатаем ответ, используя тот же алгоритм, что и для печати вопроса.

Когда все ответы напечатаны, общий размер гистограммы сохраняется в переменной $y. Теперь мы можем корректно уменьшить размер рисунка, но у нас нет функции ImageCrop(). Чтобы выйти из положения, мы создаем новую область соответствующего размера и применяем функцию ImageCopy() к той части оригинального изображения, которую мы хотим сохранить. Затем выдаем изображение соответствующего размера в формате PNG, используя функцию ImagePNG(), и удаляем все из памяти с помощью двух вызовов функции ImageDestroy().

Как упоминалось в начале этого раздела, это простая, разработанная «на скорую руку» программа для печати гистограмм. Она работает и решает некоторые проблемы, например выполняет перенос строк, но она не абсолютно безупречна. К примеру, она не очень хорошо настраивается. Многие установки зашиты непосредственно в коде. Тем не менее она демонстрирует, как совместно применять множество функций из библиотеки GD для создания полезного графического приложения.

Добавлено: 22 Июля 2018 15:24:46 Добавил: Андрей Ковальчук

Безопасная работа с изображениями

Задача
Необходимо контролировать, кто может просматривать набор изображений.

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

header('Content-Type: image/png');
readfile('/path/to/graphic.png');


Обсуждение
Первая строка в разделе «Решение» посылает броузеру заголовок Content-type, поэтому броузер знает тип прибывающего объекта и отображает его соответствующим образом. Вторая строка открывает файл на диске (или с удаленного URL) для чтения, читает его, выгружает его прямо в броузер и закрывает файл.

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

Один из способов – базовая аутентификация HTTP, которой посвящен рецепт 8.9.
Однако типичный способ не всегда самый лучший. Скажем, что произойдет, если необходимо ограничить список файлов, доступных для просмотра, а усложнение работы применением имен пользователей и паролей нежелательно? Один из вариантов состоит в том, чтобы создать ссылки на файлы – если пользователи не могут щелкнуть по ссылке, то они не могут и просмотреть файл. Но пользователи могли сделать закладки на старые файлы или приложить усилия и отгадать другие имена файлов, основываясь на вашей системе именования, и вручную ввести URL в броузере.

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

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

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

// показываем комикс, если он не старше 14 дней и не относится
// к будущим комиксам
// вычисляем текущую дату
list($now_m,$now_d,$now_y) = explode(',',date('m,d,Y'));
$now = mktime(0,0,0,$now_m,$now_d,$now_y);
// двухчасовая граница, чтобы учесть dst
$min_ok = $now - 14*86400 - 7200; // 14 дней назад
$max_ok = $now + 7200; // сегодня
// определяем временную метку запрашиваемого комикса
$asked_for = mktime(0,0,0,$_REQUEST['mo'],$_REQUEST['dy'],$_REQUEST['yr']);
// сравниваем даты
if (($min_ok > $asked_for) || ($max_ok < $asked_for)) {
echo 'You are not allowed to view the comic for that day.';
} else {
header('Content-type: image/png');
readfile("/www/comics/$_REQUEST['mo']$_REQUEST['dy']
$_REQUEST['yr'].png");
}

Добавлено: 22 Июля 2018 14:12:16 Добавил: Андрей Ковальчук

Создание и установка прозрачного цвета

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

Решение
Это делается с помощью функции ImageColorTransparent():

$color = ImageColorAllocate($image, $red, $green, $blue);
ImageColorTransparent($image, $color);


Обсуждение
И формат GIF и формат PNG поддерживают прозрачность, а формат JPEG не поддерживает. Для ссылки на прозрачный цвет в библиотеке GD предназначена константа IMG_COLOR_TRANSPARENT. Например, ниже показано, как начертить пунктирную линию, состоящую из чередующихся черных и прозрачных участков:

// чертим черно-белую пунктирную линию толщиной в два пиксела
$style = array($black, $black, IMG_COLOR_TRANSPARENT,
IMG_COLOR_TRANSPARENT);
ImageSetStyle($image, $style);


Для того чтобы определить текущие установки прозрачности, возьмите значение, возвращенное функцией ImageColorTransparent(), и передайте его функции ImageColorsForIndex():

$transparent = ImageColorsForIndex($image, ImageColorTransparent($image));
print_r($transparent);
Array
(
[red] => 255
[green] => 255
[blue] => 255
)


Функция ImageColorsForIndex() возвращает массив значений красной, зеленой и синей компонент цвета. В данном случае прозрачным является белый цвет.

Добавлено: 22 Июля 2018 14:11:18 Добавил: Андрей Ковальчук

Построение динамических изображений

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

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

// Конфигурационные настройки
$image = ImageCreateFromPNG('button.png');
$text = $_GET['text'];
$font = ImagePSLoadFont('Times');
$size = 24;
$color = ImageColorAllocate($image, 0, 0, 0); // черный
$bg_color = ImageColorAllocate($image, 255, 255, 255); // белый
// Печатаем центрированный текст
list($x, $y) = pc_ImagePSCenter($image, $text, $font, $size);
ImagePSText($image, $text, $font, $size, $color, $bg_color, $x, $y);
// Посылаем изображение
header('Content-type: image/png');
ImagePNG($image);
// Удаляем
ImagePSFreeFont($font);
ImageDestroy($image);

Обсуждение
Строить динамические изображения с помощью библиотеки GD довольно легко, достаточно объединить несколько рецептов вместе. В на-чале программы из раздела «Решение» мы загружаем изображение из запаса шаблонов кнопок; оно играет роль фона, на который накладывается текст. Считаем, что текст поступает прямо из строки запроса. В качестве альтернативы можно получить текст из базы данных (в случае счетчиков доступа) или с удаленного сервера (котировки акций или пиктограммы прогноза погоды).

После этого мы продолжаем работать с другими параметрами: загружаем шрифт и указываем его размер и цвет, а также цвет фона. Однако перед тем как печатать текст, необходимо вычислить его местоположение; функция pc_ImagePSCenter().Наконец, мы выдаем изображение и удаляем шрифт и зображение из памяти.

Например, следующий фрагмент кода генерирует HTML-страницу и теги изображения с динамическими кнопками.<?php

if (isset($_GET['button'])) {
// Параметры конфигурации
$image = ImageCreateFromPNG('button.png');
$text = $_GET['button']; // динамически сгенерированный текст
$font = ImagePSLoadFont('Times');
$size = 24;
$color = ImageColorAllocate($image, 0, 0, 0); // черный
$bg_color = ImageColorAllocate($image, 255, 255, 255); // белый
// Печатаем центрированный текст
list($x, $y) = pc_ImagePSCenter($image, $text, $font, $size);
ImagePSText($image, $text, $font, $size, $color, $bg_color, $x, $y);
// Посылаем изображение
header('Content-type: image/png');
ImagePNG($image);
// Удаляем
ImagePSFreeFont($font);
ImageDestroy($image);
} else {
?>
<html>
<head>
<title>Sample Button Page</title>
</head>

<img src="<?php echo $_SERVER['PHP_SELF']; ?>?button=Previous"
alt="Previous" width="132" height="46">
<img src="<?php echo $_SERVER['PHP_SELF']; ?>?button=Next"
alt="Next" width="132" height="46">
</html>
<?php
}
?>


В этом сценарии, если значение для переменной $_GET['button'] передано, мы генерируем кнопку и посылаем броузеру PNG. Если значение переменной $_GET['button'] не установлено, мы печатаем базовую HTML-страницу с двумя внедренными обратными вызовами сценария с запросами для каждой кнопки – один для кнопки Previous (предыдущая) и один для кнопки Next (следующая). Общим решением будет создание отдельной страницы button.php, которая возвращает только картинки и устанавливает источник изображения по адресу этой страницы.

Добавлено: 22 Июля 2018 14:10:38 Добавил: Андрей Ковальчук

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

Задача
Необходимо нарисовать текст в центре изображения.

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

Для встроенных в GD шрифтов применяется функция pc_ImageString-Center(), приведенная в примере 15.1.

Пример 15.1. pc_ImageStringCenter()

function pc_ImageStringCenter($image, $text, $font) {
// размеры шрифта
$width = array(1 => 5, 6, 7, 8, 9);
$height = array(1 => 6, 8, 13, 15, 15);
// определяем размер изображения
$xi = ImageSX($image);
$yi = ImageSY($image);
// определяем размер текста
$xr = $width[$font] * strlen($text);
$yr = $height[$font];
// вычисляем среднюю точку$x = intval(($xi - $xr) / 2);
$y = intval(($yi - $yr) / 2);
return array($x, $y);
}


Например:
list($x, $y) = pc_ImageStringCenter($image, $text, $font);
ImageString($image, $font, $x, $y, $text, $fore);


Для шрифтов PostScript следует применять функцию pc_ImagePSCenter(), показанную в примере 15.2.

Пример 15.2. pc_ImagePSCenter()
function pc_ImagePSCenter($image, $text, $font, $size, $space = 0,
$tightness = 0, $angle = 0) {
// определяем размер изображения
$xi = ImageSX($image);
$yi = ImageSY($image);
// определяем размер текста
list($xl, $yl, $xr, $yr) = ImagePSBBox($text, $font, $size,
$space, $tightness, $angle);
// вычисляем среднюю точку
$x = intval(($xi - $xr) / 2);
$y = intval(($yi + $yr) / 2);
return array($x, $y);
}


Например:
list($x, $y) = pc_ImagePSCenter($image, $text, $font, $size);
ImagePSText($image, $text, $font, $size, $fore, $back, $x, $y);


В примере 15.3 показана функция pc_ImageTTFCenter(), предназначенная для шрифтов TrueType.

Пример 15.3. pc_ImageTTFCenter()
function pc_ImageTTFCenter($image, $text, $font, $size) {
// определяем размер изображения
$xi = ImageSX($image);
$yi = ImageSY($image);
// определяем размер текста
$box = ImageTTFBBox($size, $angle, $font, $text);
$xr = abs(max($box, $box));
$yr = abs(max($box, $box));
// вычисляем среднюю точку
$x = intval(($xi - $xr) / 2);
$y = intval(($yi + $yr) / 2);return array($x, $y);
}


Например:
list($x, $y) = pc_ImageTTFCenter($image, $text, $font, $size);
ImageTTFText($image, $size, $angle, $x, $y, $fore, $font, $text);


Обсуждение
Все три функции из раздела «Решение» возвращают координаты x и y рисунка. Конечно, для вычисления этих координат применяются различные методы, в зависимости от типа шрифта, размера и настроек.

Для шрифтов PostScript Type 1 передайте функции pc_ImagePSCenter() изображение, размещенное функцией ImageCreate() (или одним из ее аналогов), и набор аргументов, определяющий способ отрисовки текста.

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

Для определения размера области изображения внутри функции применяются функции ImageSX() и ImageSY(), возвращающие ширину и высоту изображения. Затем надо вызвать функцию ImagePSBBox(). Она возвращает четыре целочисленных значения: координаты x и y крайнего левого нижнего положения текста и координаты x и y крайнего правого верхнего положения текста. Поскольку координаты отсчитываются относительно базовой линии текста, то обычно они не равны нулю. Например, буква «g» продолжается ниже границы остальных букв; поэтому в данном случае значение для нижнего левого положения отрицательное. Вооружившись этими шестью значениями, можно вычислить правильное местоположение средней точки. Поскольку координаты верхнего левого угла области отображения равны (0,0), а функции Image-PSBText() требуется левый нижний угол, то формулы определения переменных $x и $y не совпадают друг с другом. Для $x мы берем разность между размером области отображения и текста. Это дает размер пространства, окружающего текст. Затем мы делим это число пополам, чтобы определить количество пикселов, которые мы должны оставить слева от текста. Для $y мы делаем то же самое, но прибавляем переменные $yi и $yr. Добавляя эти числа, мы можем определить координату
дальней стороны прямоугольника, которая необходима в данном случае из-за обратного порядка отсчета координаты y в библиотеке GD.

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

Чтобы отцентрировать текст, соберем все вместе:function pc_ImagePSCenter($image, $text, $font,
$size, $space = 0,
$tightness = 0, $angle = 0) {
// определяем размер изображения
$xi = ImageSX($image);
$yi = ImageSY($image);
// определяем размер текста
list($xl, $yl, $xr, $yr) = ImagePSBBox($text, $font, $size,
$space, $tightness, $angle);
// вычисляем среднюю точку
$x = intval(($xi - $xr) / 2);
$y = intval(($yi + $yr) / 2);
return array($x, $y);
}
$image = ImageCreate(500,500);
$text = 'PHP Cookbook Rules!';
$font = ImagePSLoadFont('/path/to/font.pfb');
$size = 20;
$black = ImageColorAllocate($image, 0, 0, 0);
$white = ImageColorAllocate($image, 255, 255, 255);
list($x, $y) = pc_ImagePSCenter($image, $text, $font, $size);
ImagePSText($image, $text, $font, $size, $white, $black, $x, $y);
ImagePSFreeFont($font);
header('Content-type: image/png');
ImagePng($image);
ImageDestroy($image);


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

Встроенные шрифты имеют фиксированную ширину, поэтому можно
без труда определить размер символа и создать функцию, возвращаю-
щую размер текста на основании его длины.Внутри функции pc_ImageStringCenter() мы вычисляем длину строки как целое кратное от ее длины; высота – это просто высота одного символа. Обратите внимание, что функция ImageString() считает ее координату y наивысшей координатой части текста, поэтому при вычислении переменной $y надо изменить знак обратно на минус.

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

$text = 'The quick brown fox jumps over the lazy dog.';
for ($font = 1, $y = 5; $font <= 5; $font++, $y += 20) {
list($x, $y) = pc_ImageStringCenter($image, $text, $font);
ImageString($image, $font, $x, $y, $text, $color);
}


Для шрифтов TrueType необходимо использовать функцию ImageTTFBBox() или более современную функцию ImageFtBBox( ) (функция, в имени которой есть буквы «TTF», предназначена для FreeType версии 1.x; функция с буквами «Ft» применяется для FreeType версии 2.x.). Она возвращает восемь чисел: координаты (x,y) четырех углов текста, начиная с нижнего левого и далее по кругу, против часовой стрелки. Таким образом, вторые две координаты – для нижнего правого угла области и т. д.

Чтобы создать функцию pc_ImageTTFCenter(), начните с функции pc_ImagePSCenter() и замените строку:

// определяем размер текста
list($xl, $yl, $xr, $yr) = ImagePSBBox($text, $font, $size,
$space, $tightness, $angle);
на следующий фрагмент:
// определяем размер текста
$box = ImageTTFBBox($size, $angle, $font, $text);
$xr = abs(max($box, $box));
$yr = abs(max($box, $box));


Приведем пример применения функции pc_ImageTTFCenter():

list($x, $y) = pc_ImageTTFCenter($image, $text, $font, $size);ImageTTFText($image, $size, $angle, $x, $y, $white, $black,
'/path/to/font.ttf', $text);

Добавлено: 22 Июля 2018 14:09:30 Добавил: Андрей Ковальчук

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

Задача
Вывести текст как графический элемент. Это позволяет динамически отображать кнопки или счетчики выполнения.

Решение
Для встроенных шрифтов библиотеки GD применяется функция ImageString():

ImageString($image, 1, $x, $y, 'I love PHP Cookbook', $text_color);

Для шрифтов TrueType предназначена функция ImageTTFText():
ImageTTFText($image, $size, 0, $x, $y, $text_color, '/path/to/font.ttf',
'I love PHP Cookbook');


Для шрифтов PostScript Type 1 применяются функции ImagePSLoadFont() и ImagePSText():

$font = ImagePSLoadFont('/path/to/font.pfb');
ImageString($image, 'I love PHP Cookbook', $font, $size,
$text_color, $background_color, $x, $y);


Обсуждение
Для того чтобы поместить текст в область изображения, вызовите функцию ImageString(). Подобно другим функциям рисования библиотеки GD, функции ImageString() необходима обширная входная инфор-мация: область, на которой рисуют, номер шрифта, координаты x и y верхнего правого угла первой буквы, отображаемая строка и, наконец, цвет, задаваемый для рисования строки.

В случае функции ImageString() имеется пять возможных вариантов выбора шрифта, от 1 до 5. Шрифт номер 1 самый маленький, а шрифт номер 5 самый большой.Любое значение, выходящее за этот диапазон, порождает ближайший к указанному значению допустимый размер.Чтобы нарисовать текст вертикально, а не горизонтально, используйте вместо предыдущей функцию ImageStringUp().Для того чтобы со шрифтами TrueType можно было работать, необходимо также инсталлировать библиотеку FreeType и сконфигурировать
PHP во время его инсталляции для использования библиотеки FreeType. Главный сайт FreeType находится на http://www.freetype.org.

Чтобы разрешить поддержку FreeType 1.x, укажите параметр --withttf, а для FreeType 2.x – параметр --with-freetype-dir=DIR.

Подобно функции ImageString(), функция ImageTTFText() печатает строку в области отображения, но она имеет немного другие параметры, расположенные в другом порядке:
ImageTTFText($image, $size, $angle, $x, $y, $text_color, '/path/to/font.ttf',$text);

Аргумент $size представляет размер шрифта в пикселах, $angle – угол поворота в градусах в направлении, обратном направлению вращения часовой стрелки, а /path/to/font.ttf определяет путь файлу шрифта TrueType. В отличие от функции ImageString(), в данном случае точка($x,$y) – это крайние левые координаты базовой линии первой буквы.

Базовая линия определяет нижнюю границу, на которой располагается большинство символов. Такие символы, как «g» и «j», продолжаются ниже базовой линии; символы «a» и «z» находятся на базовой линии.

Шрифтам PostScript Type 1 необходима инсталляция библиотеки t1lib. Ее можно загрузить с ftp://sunsite.unc.edu/pub/Linux/libs/graphics/ и встроить в PHP с помощью параметра --with-t1lib.

И здесь тоже синтаксис печати текста похож, но не тот же самый:

$font = ImagePSLoadFont('/path/to/font.pfb');
ImagePSText($image, $text, $font, $size, $text_color,
$background_color, $x, $y);
ImagePSFreeFont($font);


Во-первых, имена шрифтов PostScript нельзя прямо передать функции ImagePSText(), они должны быть загружены с помощью функции ImagePSLoadFont(). В случае успеха функция возвращает ресурс шрифта, который может быть использован функцией ImagePSText(). Во-вторых, помимо указания цвета текста, надо передать цвет фона, который будет использован при вычислении сглаживания. Позиционирование точки ($x,$y) аналогично тому, как это делает библиотека TrueType.

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

Кроме указанных выше обязательных аргументов функция ImagePSText() принимает также четыре необязательных аргумента в следующем порядке: space, tightness, angle и antialias_steps. Необходимо включать или все четыре аргумента, или ни один из них (т. е. нельзя передать один, два или три из этих аргументов). Первый аргумент управляет размером физического интервала (т. е. пространством, образующимся после нажатия клавиши пробела); второй аргумент определяет плотность расположения букв; третий аргумент – это угол поворота в градусах в направлении, обратном направлению вращения
часовой стрелки; последний аргумент представляет собой значение для сглаживания. Это число должно быть равно или 4, или 16. Для получения более качественной картинки, но требующей больше вычислительных затрат, задайте значение 16.

По умолчанию значения space, tightness и angle равны 0. Положительное значение увеличивает расстояние между словами и буквами или поворачивает рисунок в направлении, обратном направлению вращения часовой стрелки. Отрицательное число сжимает слова и буквы или поворачивает рисунок в обратном направлении. Вывод следующего примера показан на рис. 15.7:

// нормальное изображение
ImagePSText($image, $text, $font, $size, $black, $white, $x, $y, 0, 0, 0, 4);
// дополнительное пространство между словами
ImagePSText($image, $text, $font, $size, $black, $white, $x, $y + 30,
100, 0, 0, 4);// дополнительное пространство между буквами
ImagePSText($image, $text, $font, $size, $black, $white, $x, $y + 60,
0, 100, 0, 4);

Добавлено: 22 Июля 2018 14:08:14 Добавил: Андрей Ковальчук

Рисование узорными линиями

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

Решение
Для вычерчивания фигур узорными линиями предназначена функция ImageSetStyle(), которой в качестве изображения передается параметр IMG_COLOR_STYLED:

$black = ImageColorAllocate($image, 0, 0, 0);
$white = ImageColorAllocate($image, 255, 255, 255);
// создаем черно-белую пунктирную линию толщиной в два пиксела
$style = array($black, $black, $white, $white);
ImageSetStyle($image, $style);
ImageLine($image, 0, 0, 50, 50, IMG_COLOR_STYLED);
ImageFilledRectangle($image, 50, 50, 100, 100, IMG_COLOR_STYLED);


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

$style = array($white, $black);
ImageSetStyle($image, $style);
ImageFilledRectangle($image, 0, 0, 49, 49, IMG_COLOR_STYLED);

Добавлено: 22 Июля 2018 14:07:23 Добавил: Андрей Ковальчук

Рисование дуг, эллипсов и окружностей

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

Решение
Для того чтобы нарисовать дугу, вызовите функцию ImageArc():

ImageArc($image, $x, $y, $width, $height, $start, $end, $color);


Эллипс можно нарисовать, вызвав функцию ImageArc() и установив переменную $start в 0, а переменную $end – в 360:

ImageArc($image, $x, $y, $width, $height, 0, 360, $color);


Если вызвать функцию ImageArc(), установив переменную $start в 0, переменную $end – в 360 и задав одинаковые значения для переменных $width и $height, то получится окружность:

ImageArc($image, $x, $y, $diameter, $diameter, 0, 360, $color);


Обсуждение
Функция ImageArc() отличается чрезвычайной гибкостью, – передавая ей нужные значения, можно без труда создавать простые кривые, такие как эллипсы и окружности. Как и для многих других функций библиотеки GD, первым параметром является область отображения.

Следующие два параметра – это координаты x и y центра дуги. За ними – ширина и высота дуги. Поскольку окружность – это дуга с шириной, равной высоте, то для рисования окружности установите значения обоих параметров, соответствующие диаметру окружности.

Шестой и седьмой параметры представляют начальный и конечный углы в градусах. Значение, равное 0, означает 3 часа. Затем дуга идет по часовой стрелке, так что 90° означают 6 часов, 180° означают 9 часов, а 270° соответствуют 12 часам. (Будьте осторожны! Такое поведение свойственно не всем функциям библиотеки GD. Например, при
вращении текста используется направление, обратное вращению часо-вой стрелки.) Центр дуги находится в точке ($x,$y), поэтому если вы рисуете полуокружность от 0° до 180°, ее начало будет располагаться не в точке ($x,$y), а в точке ($x+($diameter/2),$y).
Как обычно, последний параметр – это цвет дуги.

Например, следующий фрагмент рисует в центре области отображения незакрашенную черную окружность диаметром в 100 пикселов, которая изображена в левой половине рис. 15.3:

$image = ImageCreate(100,100);
$bg = ImageColorAllocate($image, 255, 255, 255);
$black = ImageColorAllocate($image, 0, 0, 0);
ImageArc($image, 50, 50, 100, 100, 0, 360, $black);


Для получения закрашенного эллипса или окружности вызывайте функцию ImageFillToBorder():

ImageArc($image, $x, $y, $diameter, $diameter, 0, 360, $color);
ImageFillToBorder($image, $x, $y, $color, $color);


Функция ImageFillToBorder() заливает область с началом в точке ($x,$y) цветом, указанным в последнем параметре, вплоть до границы области отображения, или до встречи с линией, окрашенной цветом, заданным третьим параметром.

Вставив это в предыдущие примеры, получаем:

$image = ImageCreate(100,100);
$bg = ImageColorAllocate($image, 255, 255, 255);
$black = ImageColorAllocate($image, 0, 0, 0);
ImageArc($image, 50, 50, 100, 100, 0, 360, $black);
ImageFillToBorder($image, 50, 50, $black, $black);


Пользователи версии GD 2.x могут вызвать функцию ImageFilledArc() и передать ей последний параметр, описывающий стиль заполнения.

GD 2.x поддерживает также специальные функции ImageEllipse() и ImageFilledEllipse().

Добавлено: 22 Июля 2018 14:06:39 Добавил: Андрей Ковальчук

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

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

Решение
Линию можно нарисовать посредством функции ImageLine():

ImageLine($image, $x1, $y1, $x2, $y2, $color);


Функция ImageRectangle() позволяет нарисовать незакрашенный прямоугольник:

ImageRectangle($image, $x1, $y1, $x2, $y2, $color);

А функция ImageFilledRectangle() – сплошной прямоугольник:
ImageFilledRectangle($image, $x1, $y1, $x2, $y2, $color);


Для того чтобы нарисовать незакрашенный многоугольник, вызовите функцию ImagePolygon():

$points = array($x1, $y1, $x2, $y2, $x3, $y3);
ImagePolygon($image, $points, count($points)/2, $color);

Закрашенный многоугольник можно нарисовать, вызвав функцию ImageFilledPolygon():

$points = array($x1, $y1, $x2, $y2, $x3, $y3);
ImageFilledPolygon($image, $points, count($points)/2, $color);


Обсуждение
Прототипы всех пяти функций в разделе «Решение» похожи. Первый параметр представляет собой дескриптор области отображения. Следующий набор параметров – это координаты x и y, указывающие библиотеке GD, как рисовать фигуру. В функции ImageLine() четыре координаты определяют концы линии, а в функции ImageRectangle() они
указывают противоположные углы прямоугольника. Например, вызов ImageLine($image, 0, 0, 100, 100, $color) генерирует диагональ. Передав те же самые параметры функции ImageRectangle(), получим прямоугольник с углами в точках (0,0), (100,0), (0,100) и (100,100).Функция ImagePolygon() немного отличается, поскольку она принимает переменное количество вершин. Поэтому вторым параметром является массив координат x и y. Функция начинает работу с первого набора точек и рисует линии от вершины к вершине до тех пор, пока не замкнет фигуру, возвратившись к начальной точке. Требуется по крайней мере три вершины многоугольника (всего шесть элементов массива). Третий параметр – это количество вершин в фигуре; поскольку это всегда половина числа элементов массива точек, то гибким значением для этого параметра является count($points) / 2, так как оно позволяет обновлять массив вершин, не затрагивая вызов функции ImageLine().

Наконец, все функции принимают последний параметр, определяющий цвет рисования. Обычно это значение, возвращенное функцией ImageColorAllocate(), но оно может быть представлено константами IMG_COLOR_STYLED или IMG_COLOR_STYLEDBRUSHED, если требуется нарисовать несплошные линии, что обсуждается в рецепте 15.3. Все эти функции рисуют незакрашенные фигуры. Чтобы заставить библиотеку GD заполнить фигуру цветом рисования, вызывайте функции ImageFilledRectangle() и ImageFilledPolygon() с тем же набором аргументов, что и для их незакрашенных собратьев.

Добавлено: 22 Июля 2018 14:03:37 Добавил: Андрей Ковальчук

Создание эскизов изображений c помощью PHP

Простая функция для создания эскизов изображений с сохранением пропорций.

<?php
function createThumbImg($sPath, $tPath, $tWidth, $tHeight) {
    if (strrpos($sPath, '.') !== FALSE)
        $imgType = strtolower(substr($sPath, strrpos($sPath, '.')+1));
    switch($imgType) {
        case 'jpg':
            $source = @ImageCreateFromJpeg($sPath);
            function image($image, $fileName) {
                ImageJpeg($image, $fileName);
            }
            break;
        case 'jpeg':
            $source = @ImageCreateFromJpeg($sPath);
            function image($image, $fileName) {
                ImageJpeg($image, $fileName);
            }
            break;
        case 'gif':
            $source = @ImageCreateFromGif($sPath);
            function image($image, $fileName) {
                ImageGif($image, $fileName);
            }
            break;
        case 'png':
            $source = @ImageCreateFromPng($sPath);
            function image($image, $fileName) {
                ImagePng($image, $fileName);
            }
            break;
    }
    if (!$source) return FALSE;
    $imgData = @getimagesize($sPath);
    if(!$imgData) return FALSE;
    if ($imgData[0] &gt; $imgData[1]) {
            $ratio = floatval($tWidth / $imgData[0]);
    }
    else {
            $ratio = floatval($tHeight / $imgData[1]);
    }
    $tWidth = intval($ratio * $imgData[0]);
    $tHeight = intval($ratio * $imgData[1]);
    $thumb = @ImageCreateTrueColor($tWidth, $tHeight);
    if (!$thumb) return FALSE;
    @ImageCopyResampled($thumb, $source, 0, 0, 0, 0, $tWidth, $tHeight, $imgData[0], $imgData[1]);
    Image($thumb, $tPath);
    return TRUE;
}

Добавлено: 05 Июля 2018 07:38:39 Добавил: Андрей Ковальчук

Преобразование изображения в черно-белое на PHP

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

Максимальный размер изображения - 50кб [Снять ограничение*]
Исходное изображение:
Поддерживаемые форматы: JPEG, GIF, PNG.

*За 11 рублей снимается ограничение на максимальный размер.
Вы сможете производить преобразования любого количества изображений без ограничения на размер до закрытия окна браузера.
Также снимаются ограничения на Создание анимированной gif-картинки и на изменение размера изображения.

<?php
#this file outputs a grey version of specified image
#use of this file:
#  in the image tag, <img border=0 src=greyimage.php3?src=imagesrc&col=colno >
# where imagesrc is the source of the original colour version
# where colno is 0 for grey, 1 for red, 2 green, 3 blue

function MakeColoursGrey($im,$col){
 $total=ImageColorsTotal($im);
 for($i=0;$i<$total;$i++){
   $old=ImageColorsForIndex($im,$i);

   #trying to keep proper saturation when converting
   $commongrey=(int)($old['red']+$old['green']+$old['blue'])/3;
   if(!$col){
    ImageColorSet($im,$i,$commongrey,$commongrey,$commongrey);
   }elseif($col==1){
    ImageColorSet($im,$i,$commongrey,0,0);
   }elseif($col==2){
    ImageColorSet($im,$i,0,$commongrey,0);
   }elseif($col==3){
    ImageColorSet($im,$i,0,0,$commongrey);
   }
 }
}

$img=imagecreatefromgif($src);

#change the colours to grey
MakeColoursGrey($img,$col);

#send the http header, this outputs an image of type gif
Header("Content-Type: image/gif");

#send the image
ImageGif($img);
?>

Добавлено: 03 Июля 2018 08:25:50 Добавил: Андрей Ковальчук

Круговая диаграмма средствами библиотеки GD

В случае, если необходимо отобразить процентное соотношение каких-либо параметров, не обойтись без круговой диаграммы. Строить ее совсем не трудно, если знать о существовании функций библиотеки GD imagearc и imagefilledarc, которые рисуют дугу и закрашенную дугу соответственно. В качестве параметров функции imagearc(int im, int cx, int cy, int w, int h, int s, int e, int col) нужно указать: im - идентификатор области рисования; cx, cy - координаты центра дуги; w, h - ширину и высота дуги (для построения сектора круга они должны быть равны); s, e - начальный и конечный углы дуги (в градусах, от 0 до 360) и конечно же col - цвет дуги. Функция imagefilledarc() отличается от предыдущей лишь наличием дополнительного параметра style, который определяет способ заливки сектора. Этот параметр может принимать следующие значения:

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

Эти параметры можно указывать, используя оператор || (ИЛИ).

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

<?php

function drawSegment($x0,$y0,$radius,$begAngle,$endAngle,$color) {
global $im,$x0,$y0,$black;
//рисуем сектор круга соответствующих размера и цвета
imagefilledarc($im, $x0, $y0, $radius*2, $radius*2,
    $begAngle, $endAngle,
    $color, IMG_ARC_PIE);
//рисуем окантовку черным цветом
//для выведенного ранее сектора
imagefilledarc($im, $x0, $y0, $radius*2, $radius*2,
    $begAngle, $endAngle,
    $black, IMG_ARC_EDGED | IMG_ARC_NOFILL);
}

Добавлено: 03 Июля 2018 07:55:39 Добавил: Андрей Ковальчук