Php водяные знаки на изображении

Создание водяных знаков с помощью PHP

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

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

Для справки

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

Информация, находящаяся в альфа-канале чаще всего представляет выделенные области — некоторые формы или расположение цветных областей. Сохранение альфа-канала в изображении увеличивает размер файла на 1/3. RGB изображения могут иметь до 24 альфа-каналов. Точечные и индексированные изображения не могут содержать альфа-каналов.

Часть первая — основы

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

# возвращает ширину и высоту изображения imagesx() imagesy() # создаёт новое изображение true-color imagecreatetruecolor # возвращает ассоциативный массив с ключами red, green и blue (+ альфа-канал), # содержащими соответствующие значения для специфицированного индекса цвета imagecolorsforindex() # возвращает индекс цвета пиксела в специфицированном месте в изображении imagecolorat() # рисует одиночный пиксел заданного цвета imagesetpixel() # возвращает индекс индекс цвета в палитре изображения, # идентификатор цвета (составленный из RGB-компонентов) # и индекс цвета палитры изображения, # являющегося "ближайшим" к RGB-значению соответственно # (эти данные необходимы для функции imagesetpixel() ) imagecolorexact() imagecolorallocate() imagecolorclosest()

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

Постановка задачи

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

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

Читайте также:  Java functional interface consumer

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

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

Думаю, теории уже достаточно — ключевые моменты в ней раскрыты достаточно подробно. Теперь перейдем непосредственно к написанию скрипта.

Часть вторая — пишем скрипт

Начнем с самого простого — напишем класс, который создает файл с водяным знаком. Назовем его «watermark» и пропишем его код в файле “api.watermark.php”. «Скелетом» класса будет три функции:

 # функция для "усреднения" цветов изображений function _get_ave_color() < ># функция, которая находит ближайшие RGB-цвета для нового изображения function _get_image_color() < >> ?>

Следующим этапом будет написание кода функций класса «watermark». Дополняем файл “api.watermark.php” следующими строками кода:

# функция, которая сливает два исходных изображения в одно function create_watermark($main_img_obj, $watermark_img_obj, $alpha_level=100) < $alpha_level/= 100; # переводим значение прозрачности альфа-канала из % в десятки # расчет размеров изображения (ширина и высота) $main_img_obj_w = imagesx( $main_img_obj ); $main_img_obj_h = imagesy( $main_img_obj ); $watermark_img_obj_w = imagesx( $watermark_img_obj ); $watermark_img_obj_h = imagesy( $watermark_img_obj ); # определение координат центра изображения $main_img_obj_min_x = floor(($main_img_obj_w/2)-($watermark_img_obj_w/2)); $main_img_obj_max_x = ceil(($main_img_obj_w/2)+($watermark_img_obj_w/2)); $main_img_obj_min_y = floor(($main_img_obj_h/2)-($watermark_img_obj_h/2)); $main_img_obj_max_y = ceil(($main_img_obj_h/2)+($watermark_img_obj_h /2)); # создание нового изображения $return_img = imagecreatetruecolor($main_img_obj_w, $main_img_obj_h); # пройдемся по исходному изображению # "некоторый код" # отображаем изображение с водяным знаком return $return_img; ># конец функции create_watermark()

Теперь подробнее рассмотрим функцию create_watermark().
Первым делом мы передаем ей три параметра:

$main_img_obj # исходное изображение, на которое нужно поставить водяной знак $watermark_img_obj # сам водяной знак, должен содержать альфа-канал $alpha_level # значение прозрачности альфа-канала водяного знака, (0-100, по умолчнию = 100)

(Важно отметить, что наша функция принимает изображения как объекты, а не просто как пути к ним – но об этом будет сказано чуть позже)

Далее мы нам необходимо получить информацию об каждом из изображений. Нам это необходимо знать координаты X и Y для расположения водяного знака в центре исходного изображения.

Следующим этапом будет создание нового, true-color изображения с теми же размерами, как и у исходной картинки. Это изображение (переменная $return_img) будет использовано для объединения информации из исходных картинок (рисунок и водяной знак).

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

Читайте также:  и

Финалом будет отображения нашего модифицированного изображения в веб-странице, которая его запросит. Далее рассмотрим оставшиеся две вспомогательные функции.

Часть третья — вспомогательные функции

Помимо функции create_watermark в нашем классе watermark присутствуют еще две функции. Продолжим исходный код класса следующими строками:

# усреднение двух цветов с учетом прозрачности альфа-канала function _get_ave_color( $color_a, $color_b, $alpha_level ) < return round((($color_a * (1 - $alpha_level)) + ($color_b * $alpha_level))); ># возвращаем значения ближайших RGB-составляющих нового рисунка function _get_image_color($im, $r, $g, $b)

А теперь подробнее. Наша первая функция “_get_ave_color” принимает численные величины двух цветов и альфа-канала. Возвращает же она усредненную их величину. Эта функция нам необходима для определения цвета, который получится при наложении пикселей двух рисунков.

Вторая функция “_get_image_color” разбивает изображение на red (красный), green (зеленый) и синий (blue) составляющие (rgb-палитра). С помощью встроенных в php функций для работы с графикой (их описание было в начале статьи) получаем ближайшее значение цвета для нового изображения.

В дополнение еще проверяется несколько моментов. Во-первых, если удалось получить точное значение (переменная $c), то оно и возвращается из функции (return $c). В противном случае далается попытка подобрать цвет с помощью функции imagecolorallocate(). Если же и это не поможет достичь результата, то с помощью функции imagecolorclosest() просто возвращается ближайшее значение цвета (самое неточное).

Ну вот, наш класс и почти готов. Осталось только заменить в функции “create_watermark” комментарий «некоторый код» следующими строками:

# пройдемся по изображению for( $y = 0; $y < $main_img_obj_h; $y++ ) < for ($x = 0; $x < $main_img_obj_w; $x++ ) < $return_color = NULL; # определение истинного расположения пикселя в пределах нашего водяного знака $watermark_x = $x - $main_img_obj_min_x; $watermark_y = $y - $main_img_obj_min_y; # выбор информации о цвете для наших изображений $main_rgb = imagecolorsforindex($main_img_obj, imagecolorat($main_img_obj, $x, $y)); # если наш пиксель водяного знака непрозрачный if ($watermark_x >= 0 && $watermark_x < $watermark_img_obj_w && $watermark_y >= 0 && $watermark_y < $watermark_img_obj_h ) < $watermark_rbg = imagecolorsforindex( $watermark_img_obj, imagecolorat( $watermark_img_obj, $watermark_x, $watermark_y ) ); # использование значения прозрачности альфа-канала $watermark_alpha = round( ( ( 127 - $watermark_rbg['alpha'] ) / 127 ), 2 ); $watermark_alpha = $watermark_alpha * $alpha_level; # расчет цвета в месте наложения картинок $avg_red = $this->_get_ave_color( $main_rgb['red'], $watermark_rbg['red'], $watermark_alpha ); $avg_green = $this->_get_ave_color( $main_rgb['green'], $watermark_rbg['green'], $watermark_alpha ); $avg_blue = $this->_get_ave_color( $main_rgb['blue'], $watermark_rbg['blue'], $watermark_alpha ); # используя полученные данные, вычисляем индекс цвета $return_color = $this->_get_image_color( $return_img, $avg_red, $avg_green, $avg_blue ); # если же не получиться выбрать цвет, то просто возьмем копию исходного пикселя > else < $return_color = imagecolorat( $main_img_obj, $x, $y ); ># из полученных пикселей рисуем новое изоборажение imagesetpixel($return_img, $x, $y, $return_color ); > >

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

Читайте также:  Php get all defined vars

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

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

Для определения цвета области пересечения, сначала нужно получить значение RGB-переменной водяного знака, используя информацию, которую мы получили в циклах ‘for’. Потом с помощью функции «_get_ave_color” определяется среднее значение цвета для нового изображения. Далее следует функция “_get_image_color” для определения цветовой гаммы, которая будет использована функцией “return_img”.

В итоге, после завершения работы циклов ‘for’ у нас есть готовое изображение с водяным знаком.

А теперь проверим наш класс в деле.

Часть четвертая — тест-драйв

Для начала нам потребуются два файла. Первый назовем “watermark_test.php” и разместим в нем следующий код:

Назначения этотго файла очень простое: он отображает в браузере исходное (main.jpg) и полученное (watermark.png, с водяным знаком) изображения.

Как можно увидеть, наше второе изображение (watermark.png) ссылается на php-файл image.php, а не на файл-изображение. Эта ссылка имеет вид GET-запроса, где в php-файл передаются значения двух переменных: $main и $watermark.

Второй файл назовем “image.php” и и разместим в нем такой код:

create_watermark( $main_img_obj, watermark_img_obj, 66 ); # отобразим наше полученное изображение в браузере - но сначала сообщим ему, что это jpeg-файл header( 'Content-Type: image/jpeg' ); header( 'Content-Disposition: inline; filename=' . $_GET['src'] ); imagejpeg( $return_img_obj, '', 50 ); ?>

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

https://www.php.net/manual/en/function.imagecreatefromgif.php
https://www.php.net/manual/en/function.imagecreatefromjpeg.php
https://www.php.net/manual/en/function.imagecreatefrompng.php

Чтобы протестировать наш скрипт, просто запустите в браузере файл “watermark_test.php”. Как результат, должно быть два изображения — исходное и с водяным знаком.

Источник

Оцените статью