Как наложить водяной знак на изображение с помощью PHP

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

Итак, по порядку. У нас есть папка, допустим, images, в которой находятся все изображения сайта, но пока еще без водяного знака. В ней же у нас будут лежать сам скрипт и все необходимые ему файлы. Сперва нам нужно создать там папку для кэша (т.е. куда мы будем складывать уже готовые изображения, чтобы в последующем брать отсюда, а не лепить заново эти водяные знаки). Я назвал ее cache, вы можете обозвать как угодно :) Не забудьте дать ей права 777, чтобы скрипт мог сохранять туда изображения.

Далее создадим файл .htaccess (кто не знает, что это и для чего нужно, погуглите, очень полезная вещь, с его помощью мы можем задавать различные настройки сервера). В нем пропишем 2 строки, которые будут все запросы вида http://moisait.ru/images/kartinka.jpg обрабатывать как запросы http://moisait.ru/images/image.php?img=kartinka

В этом уроке мы работаем только с jpg, но вам ничего не мешает расширить возможности скрипта ;)

Содержимое файла .htaccess

 
RewriteEngine on
RewriteRule ^(.+)\.jpg$ image.php?img=$1 [NC,L]
 

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

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

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

imagecreatefromjpeg (string $filename) - возвращает идентификатор изображения, полученного из файла $filename, т.е. в результате выполнения этой функции у нас будет переменная типа resource (resource содержит специальные указатели на открытые файлы, соединения с БД, области изображения и прочее);

imagecreatefromgif (string $filename) - то же самое, только ресурс берется из gif-файла;

imagejpeg (resource $image [, string $filename [, int $quality]]) - выводит изображение в браузер или файл из переменной $image (переменная типа resource, см. выше, если забыл, что это);

Аргументы $filename и $quality необязательны.

$quality может иметь значение от 0 (наихудшее качество, наименьший по весу файл) до 100 (наилучшее качество, наибольший по весу файл). По умолчанию используется значение около 75.

Если $filename опущен, поток изображения выводится напрямую (в нашем случае в браузер). Но если же вы хотите при этом указать $quality, то для пропуска аргумента filename используйте пустую строку ('') или null.

getimagesize (string $filename [, array $imageinfo]) - получает размер изображения (GIF, JPG, PNG, SWF, PSD, TIFF или BMP) и возвращает массив из 4 элементов. Индекс 0 содержит ширину/width изображения в пикселах. Индекс 1 возвращаемого массива содержит высоту/height. Индекс 2 это флаг, указывающий тип изображения (1 - GIF, 2 - JPG, 3 - PNG, 4 - SWF, 5 - PSD, 6 - BMP, 7 - TIFF с байтовым порядком intel, 8 - TIFF с байтовым порядком motorola, 9 - JPC, 10 - JP2, 11 - JPX). Индекс 3 это текстовая строка с корректной строкой height="yyy" width="xxx", которая может использоваться непосредственно в тэге IMG.

Пример:

$info = getimagesize($image);
// итог: $info = array ( 0 => 800, 1 => 600, 2 => 2, 3 => 'height="600" width="800"');
 

imagecopymerge (resource $dst_im, resource $src_im, int $dst_x, int $dst_y, int $src_x, int $src_y, int $src_w, int $src_h, int $pct) - копирует и объединяет часть изображения.

Если подробнее, то функция копирует часть изображения $src_im (сокр. source image) в $dst_im (сокр. destination image), начиная с x,y-координат $src_x и $src_y, шириной $src_w и высотой $src_h. Эта часть будет скопирована в x,y-координаты $dst_x и $dst_y. Два изображения будут объединены в соответствии с аргументом $pct (сокр. opacity), который может иметь значение в диапазоне от 0 до 100. Если $pct = 0, действие не выполняется; если 100, эта функция работает идентично imagecopy(). То есть по сути аргументом $pct мы определяем прозрачность.

imagedestroy (resource $image) - разрушает изображение, освобождает память, ассоциированную с изображением $image.

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

  1. Проверяем, существует ли картинка, за которой пришел запрос (может, какой-то дурень написал адрес с ашыпками)
  2. Проверяем, есть ли картинка с уже наложенным вотермарком в кэше:
    1. Если есть, то просто выводим ее на экран
    2. Если нет, то накладываем вотермарк, сохраняем в кэш, и опять же выводим на экран 

Видите, все просто :)

Далее я привожу код файла image.php с подробными комментариями:

 
<?php

error_reporting(0); // это для того, чтобы скрипт не выводил возможные ошибки, нам нужно просто выдать картинку, или не выдать ее, если что-то пойдет не так

$img = preg_replace('/[\.]/', '', $_GET['img']); // это для пущей безопасности. Если вы не можете обойтись без точек в имени файла, то хотя бы позаменяйте двойные точки (..) одинарными (.)

if ( !file_exists($_GET['img'].'.jpg') )
 exit; // если такой картинки нет, то тупо вырубаемся, незачем тратить время на некорректные запросы

if ( file_exists('cache/'.$img.'.jpg') ) // здесь мы проверяем, существует ли картинка с уже наложенным водяным знаком в папке cache, и если да, то...
{
 $image = imagecreatefromjpeg('cache/'.$img.'.jpg'); // получаем ее идентификатор
 header('Content-Type: image/jpeg'); // отправляем браузеру HTTP заголовок ответа, мол, щас будет картинка
 imagejpeg($image, null, 100); // и выливаем эту картинку браузеру
 exit; // за сим разрешите откланяться :)
}
else // если же нет такой картинки в кэше
{
 $size = getimagesize($img.'.jpg'); // получаем размеры изображения
 $height = $size[1]; // высота
 $width = $size[0]; // ширина
 
 if ( $width > 200 and $height > 200 ) // убеждаемся, что она больше определенного размера, т.к. нет смысла накладывать водяной знак на слишком маленькие рисунки
 {
 // Настраиваем основные переменные и размещение
 $image_src = $img.'.jpg';
 $watermark_src = 'water.gif';
 $opacity = 40;
 
 // Загружаем изображения 
 $image = imagecreatefromjpeg($image_src);
 $watermark = imagecreatefromgif($watermark_src);
 
 // Введем и сохраним высоту и ширину наших изображений
 list($watermark_width, $watermark_height) = getimagesize($watermark_src);
 
 // Установим окончательную позицию водного знака в зависимости от отступов и размера 
 $final_x = $width - 180;
 $final_y = $height - 40;
 
 // Скопируем наш водный знак на оригинальное изображение
 imagecopymerge($image, $watermark, $final_x, $final_y, 0, 0, $watermark_width, $watermark_height, $opacity);
 
 //Настраиваем элемент header, выводим изображение, освобождаем память
 if ( !file_exists('cache') )
 {
 mkdir('cache', 0777); // если папка cache куда-то запропастилась, создаем ее
 }
 
 imagejpeg($image, 'cache/'.$img.'.jpg', 100);
 
 header('Content-Type: image/jpeg');
 imagejpeg($image);
 
 imagedestroy($image);
 imagedestroy($watermark);
 }
 else // ну а если изображение слишком маленькое, то просто выдаем его
 {
 $image = imagecreatefromjpeg($img.'.jpg');
 header('Content-Type: image/jpeg');
 imagejpeg($image, null, 100);
 }
}

?>
 

Ну вот и все! Исходник скачать можно здесь, а я как всегда открыт для ваших вопросов и пожеланий :)

З.Ы. Вы также можете видоизменить этот скрипт так, чтобы вотермарк накладывался при загрузке картинки на сервер через какую-нибудь админ-панель. Спасибо за внимание =)

 Жду с нетерпением
ваших комментариев!
 

Подписаться на RSS

Вы можете нажать "подписаться", чтобы следить за моими новостями!
Так вы всегда будете в курсе появления новостей на сайте =)
О том, что такое RSS можно прочитать здесь.

Подписаться

Подписаться на Twitter

Я специально зарегистрировался в Твиттере, чтобы вы могли следить за обновлениями на сайте =)

Подписаться

Envato marketplace А эти люди занимаются прокатом карнавальных костюмов и масок в Минске. К слову, я им делал сайт.