Нанесение водяных знаков на изображение средствами PHP

Нанесение водяных знаков на изображение средствами PHP

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

скачать исходникискачать урок

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

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

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

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

Это изображение формата PNG с 50% степенью прозрачности.

Подготовка к написанию скрипта

Первым делом необходимо убедиться, что в Вашем интерпретаторе языка PHP подключена библиотека GD. Данная библиотека используется для работы с изображениями средствами языка PHP. Поэтому если Вы не уверены, что данная библиотека подключена, откройте конфигурационный файл языка PHP и найдите строку: extension=php_gd2.dll

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

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title></title>
</head>
<body>
<img src="img/img1.jpg">
</body>
</html>

Но если мы хотим динамически наносить на изображение водяной знак и при этом не изменять исходное изображение, значит, изображение должно обрабатываться скриптом на языке PHP. Поэтому в теге img необходимо изменить значение атрибута src. То есть значение данного атрибута должно указывать не на изображение, а на файл, который обработает исходное изображение и нанесет на него водяной знак. И конечно же вернет новое изображение. Поэтому перепишем тег img:

<img src="image.php?image=img1.jpg">

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

<?php
define("DIR_IMG","img/");
define("WM",DIR_IMG."watermark.png");
?>

Данный фал нам необходим для хранения некоторых настроек, а именно:

DIR_IMG – папка где содержатся все изображения;

WM – путь к изображения, которое используется как водяной знак.

Затем создадим еще один файл – functions.php, который будет содержать в себе необходимые функции для работы скрипта. Теперь создадим файл image.php и первым делом подключим только что созданные файлы к нему.

include "config.php";
include "functions.php";

Далее проверим наличие ячейки image в суперглобальном массиве $_GET, если данная ячейка есть, то создадим переменную и сохраним в нее значение данной ячейки:

if($_GET['image']) {
	$image_for_wm = DIR_IMG.$_GET['image'];
}

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

get_water($image_for_wm);

Теперь переходим непосредственно к написанию функции get_water(), которая обработает исходное изображение и нанесет на него водяной знак.

Функция наложения водяного знака

Итак, переходим в файл functions.php и начнем создавать функцию get_water():

function get_water($main_img_path, $load = FALSE) {
	$main_img = getimagesize($main_img_path);
}

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

$main_img_path – путь к исходному изображению, которое требуется обработать;

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

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

То есть в ячейках 0 и 1 содержится ширина и высота данного изображения. В ячейке 2 одна из констант типа изображения (в нашем случае значение 2 соответствует типу jpeg). Индекс 3 содержит строку со значениями ширины и высоты изображения width=»xxx» height=»yyy», которая может быть использована внутри img тэга. Ячейка mime – содержит в себе соответствующий MIME-тип изображения.

Далее весь код будем вести внутри функции get_water(). Теперь необходимо проверить, не вернула ли функция getimagesize() – FALSE. Если да, то выходим из скрипта:

if(!$main_img) {
		exit();
	}

Далее в соответствии с MIME-типом изображения создаем на основе исходного изображения — новое изображение в памяти. Для этого мы используем оператор switch() и функции создания нового изображения на основе заданного в соответствии с его типом:

switch($main_img['mime']) {
		case 'image/jpeg':
		case 'image/pjpeg':
			$img = imagecreatefromjpeg($main_img_path);
		break;
		
		case 'image/png':
		case 'image/x-png':
			$img = imagecreatefrompng($main_img_path);
		break;	
		
		case 'image/gif':
			$img = imagecreatefromgif($main_img_path);
		break;	
	}

Обратите внимание, что для MIME-типа ‘image/jpeg’, как и для ‘image/png’, нужно учитывать и дополнительные типы (‘image/pjpeg’ и ‘image/x-png’), которые может нам вернуть браузер Internet Explorer. Далее создаем изображение в памяти из заготовленного изображения под водяной знак:

if(file_exists(WM)) {
		$water = imagecreatefrompng(WM);
	}

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

$res_width = $main_img[0];
$res_height = $main_img[1];

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

$water_width = imagesx($water);
$water_height = imagesy($water);

Затем создаем пустое полноцветное изображение, с размерами равными размерам исходного изображения:

$res_img = imagecreatetruecolor($res_width,$res_height);

Теперь остается перенести исходное изображение на только что созданное:

imagecopyresampled($res_img,$img,0,0,0,0,
$res_width,$res_height,$main_img[0],$main_img[1]);

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

$res_img – дискриптор изображения на которое выполняется копирование (изображение приемник, то которое мы только что создали);

$img – копируемое изображение (источник);

0 — x-координата изображения на которое выполняется копирование (точка по оси x в которую будет помещено копируемое изображение);

0 — y-координата изображения на которое выполняется копирование (точка по оси y в которую будет помещено копируемое изображение);

0 — x-координата изображения источника (точка по оси x c которой будет выполнено копирование);

0 — y-координата изображения источника (точка по оси y c которой будет выполнено копирование);

$res_width – ширина участка изображения приемника, куда будет помещено копируемое изображение;

$res_height — высота участка изображения приемника, куда будет помещено копируемое изображение;

$main_img[0] – ширина участка копируемого изображения (в нашем случае указываем полную ширину, так как нам необходимо скопировать все изображения, а не его часть);

$main_img[1] — высота участка копируемого изображения (в нашем случае указываем полную высоту, так как нам необходимо скопировать все изображения, а не его часть);

Далее, нам необходимо перенести водяной знак:

imagecopy($res_img,$water,$res_width-$water_width,$res_height-$water_height,
0,0,$water_width,$water_height);

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

$res_img – дискриптор изображения, на которое выполняется копирование (изображение приемник, то которое мы только что создали);

$water – дискриптор копируемого изображения;

$res_width-$water_width – координата по оси х, на изображении приемнике, в которую будет помещено копируемое изображение;

$res_height-$water_height — – координата по оси у, на изображении приемнике, в которую будет помещено копируемое изображение;

0 — x-координата изображения источника (точка по оси x c которой будет выполнено копирование);

0 — y-координата изображения источника (точка по оси y c которой будет выполнено копирование);

$water_width — ширина участка копируемого изображения (в нашем случае указываем полную ширину, так как нам необходимо скопировать все изображения, а не его часть);

$water_height — высота участка копируемого изображения (в нашем случае указываем полную высоту, так как нам необходимо скопировать все изображения, а не его часть).

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

if(!$load) {
		header("Content-Type:image/jpeg");
		imagejpeg($res_img,NULL,100);
	}
	else {
		imagejpeg($res_img,DIR_IMG.$load,100);
	}

То есть, если мы не передадим при вызове функции параметр $load, значит, изображение будет выведено на экран. Если же передать через параметр $load имя файла, значит, новое изображение будет сохранено под этим именем. Теперь давайте откроем в браузере файл index.php и посмотрим, как отрабатывает наш скрипт:

Как Вы видите, все отлично работает. На всякий случай приведу полный код данной функции:

function get_water($main_img_path, $load = FALSE) {
	$main_img = getimagesize($main_img_path);
	
	if(!$main_img) {
		exit();
	}
	
	switch($main_img['mime']) {
		case 'image/jpeg':
		case 'image/pjpeg':
			$img = imagecreatefromjpeg($main_img_path);
		break;
		
		case 'image/png':
		case 'image/x-png':
			$img = imagecreatefrompng($main_img_path);
		break;	
		
		case 'image/gif':
			$img = imagecreatefromgif($main_img_path);
		break;	
	}
	
	if(file_exists(WM)) {
		$water = imagecreatefrompng(WM);
	}
	
	$res_width = $main_img[0];
	$res_height = $main_img[1];
	
	$water_width = imagesx($water);
	$water_height = imagesy($water);
	
	$res_img = imagecreatetruecolor($res_width,$res_height);
	
	imagecopyresampled($res_img,$img,0,0,0,0,$res_width,$res_height,
	$main_img[0],$main_img[1]);
	
	imagecopy($res_img,$water,$res_width-$water_width,$res_height-$water_height,
	0,0,$water_width,$water_height);
	
	
	if(!$load) {
		header("Content-Type:image/jpeg");
		imagejpeg($res_img,NULL,100);
	}
	else {
		imagejpeg($res_img,DIR_IMG.$load,100);
	}
	
}

Сохранение обработанного изображения в файле

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

<?php
include "config.php";
include "functions.php";

if($_FILES['load']) {
	if(move_uploaded_file($_FILES['load']['tmp_name'],DIR_IMG.$_FILES['load']['name'])) {
		get_water(DIR_IMG.$_FILES['load']['name'],'wm_'.$_FILES['load']['name']);
	}
}

?>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title></title>
<meta name="" content="">
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
</head>
<body>
<form method="POST" enctype="multipart/form-data">
	<input type="file" name="load">
	<input type="submit">
</form>
</body>
</html>

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

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

Фреймворк YII2: теория и первая практика

Овладейте азами фреймворка Yii2 за 5 дней!

Получить

Метки:

Комментарии Вконтакте:

Комментарии Facebook:

Комментарии (14)

  1. Василий

    Очень интересная статья, и для меня это очень удивительно, поскольку я даже не представлял, что такое возможно. Спасибо.

  2. Виктор Гавриленко

    Здравствуйте!
    Спасибо Вам за комментарий!
    Это один из многочисленных примеров использования библиотеки GD языка PHP.

    • Василий

      Виктор. Извиняюсь за вопрос не к месту. Для моего сайта я хочу сделать форму обратной связи с НАДЕЖНОЙ капчей. У вас тут есть информация об этом? Если нет, то буду признателен если сделаете. У меня на сайте была страница с формой обратной связи, но в один прекрасный момент капча перестала выполнять роль защиты от спама.

  3. htmaker

    Хороший пост!

  4. Сергей

    здорово!

  5. Сергей

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

  6. Сергей

    а как сделать чтобы load по несколько штук за раз загружал..

  7. Сергей

    вы здесь не отвечаете?

    • Андрей Кудлай

      Сергей, задайте вопрос на нашем форуме, там удобнее решать вопросы подобного рода.

  8. Сергей

    я не могу зарегится, у Вас капча в неодеквате могу кучу скринов прислать((

    • Андрей Кудлай

      С капчей все в порядке, другие пользователи ведь регистрируются. Вы нам писали в службу поддержки. Напишите еще раз и скиньте доступ к Вашему компьютеру через TeamViewer, я подключусь, и мы попробуем зарегистрироваться вместе. Мне почему-то кажется, что вместе у нас получится)

  9. Сергей

    Виктор вы динамически выводите изображение с помощью:

    как мне поступить если оно у меня выводится иначе
    <img src="product["img"]?>» alt=»product["title"]?>»/>

  10. [email protected]

    Отличный урок! Виктор, я пытаюсь приклеить данные из формы к изображению. Не подскажете как это лучше всего сделать используя библиотеку GD?
    Заранее благодарен!

    • Виктор Гавриленко

      Здравствуйте!
      В библиотеке GD есть специальные функции, которые позволяют добавить текст непосредственно на изображение. К примеру imagefttext()

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Я не робот.

Spam Protection by WP-SpamFree