Blog. Just Blog

Нанесение графических водяных знаков на изображение

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Web-мастеру и не только | Автор: ManHunter
Наносить текстовые надписи на картинки средствами PHP мы уже умеем. Теперь рассмотрим как делать то же самое, только на этот раз вместо текста будет графический маркер. Сам маркер представляет собой картинку в формате PNG-8 (глубина цвета - 8 бит), допускается прозрачность и произвольная форма. Если маркер будет с другой глубиной цвета, то при наложении прозрачный цвет будет заменен на черный. Другой формат маркеров не поддерживается! Файл PNG определяется по расширению, можно анализировать внутреннюю структуру, но это, наверное, в данном случае лишнее и остается на совести вебмастера.
  1. //-------------------------------------------------------------------
  2. // Функция нанесения графического водяного знака на изображение
  3. // Copyright (C) ManHunter / PCL
  4. // http://www.manhunter.ru
  5. //-------------------------------------------------------------------
  6. // Параметры вызова:
  7. // $picture - путь к файлу картинки на сервере
  8. // $marker - путь к файлу водяного знака на сервере
  9. // $opacity - процент прозрачности
  10. // $watermark_position - положение водяного знака на картинке
  11. //-------------------------------------------------------------------
  12.  
  13. // Константы положения водяного знака на картинке
  14. define ("WATERMARK_LEFT_BOTTOM",0);
  15. define ("WATERMARK_LEFT_TOP",1);
  16. define ("WATERMARK_RIGHT_BOTTOM",2);
  17. define ("WATERMARK_RIGHT_TOP",3);
  18. define ("WATERMARK_CENTER",4);
  19.  
  20. function Watermark_PNG_Image($picture$marker$opacity=100,
  21.                            $watermark_position=WATERMARK_RIGHT_BOTTOM) {
  22.   // Проверки на наличие файлов и допустимые параметры
  23.   if (!file_exists($picture)) { return false; }
  24.   if (!file_exists($marker)) { return false; }
  25.  
  26.   // Получить размеры исходного изображения
  27.   list ($sx,$sy)=GetImageSize($picture);
  28.   if ($sx==|| $sy==0) { return false; }
  29.  
  30.   // Получить размеры маркера
  31.   list ($mx,$my)=GetImageSize($marker);
  32.   if ($mx==|| $my==|| $sx<($mx+20) || $sy<($my+20)) { return false; }
  33.  
  34.   // Если расширение маркера не .PNG, то выход с ошибкой
  35.   if (strtolower(substr($marker,-4))!=".png") { return false; }
  36.  
  37.   // Если расширения нет, то выход с ошибкой
  38.   $pocket=Array();
  39.   eregi("\.([a-z]*)$",$picture,$pocket);
  40.   if ($pocket[1]=="") { return false; }
  41.  
  42.   // На основании расширения создать картинку
  43.   switch (strtolower($pocket[1])) {
  44.     case "jpeg":
  45.     case "jpg": {
  46.       if (!$im=@ImageCreateFromJpeg($picture)) { return false; }
  47.       break;
  48.     }
  49.     case "gif": {
  50.       if (!$im=@ImageCreateFromGif($picture)) { return false; }
  51.       break;
  52.     }
  53.     case "png": {
  54.       if (!$im=@ImageCreateFromPng($picture)) { return false; }
  55.       break;
  56.     }
  57.     default: { return false; }
  58.   }
  59.  
  60.   // Получить координаты блока на картинке для нанесения надписи
  61.   switch ($watermark_position) {
  62.     case WATERMARK_LEFT_BOTTOM: {
  63.       $pos_x=10;
  64.       $pos_y=$sy-$my-10;
  65.       break;
  66.     }
  67.     case WATERMARK_RIGHT_BOTTOM: {
  68.       $pos_x=$sx-$mx-10;
  69.       $pos_y=$sy-$my-10;
  70.       break;
  71.     }
  72.     case WATERMARK_LEFT_TOP: {
  73.       $pos_x=10;
  74.       $pos_y=10;
  75.       break;
  76.     }
  77.     case WATERMARK_RIGHT_TOP: {
  78.       $pos_x=$sx-$mx-10;
  79.       $pos_y=10;
  80.       break;
  81.     }
  82.     case WATERMARK_CENTER: {
  83.       $pos_x=intval($sx/2-$mx/2);
  84.       $pos_y=intval($sy/2-$my/2);
  85.       break;
  86.     }
  87.     default: {
  88.       imageDestroy($im);
  89.       return false;
  90.     }
  91.   }
  92.  
  93.   // Нанести водяной знак с нужной прозрачностью
  94.   $watermark=@ImageCreateFromPng($marker);
  95.   ImageCopyMerge($im$watermark$pos_x$pos_y00$mx$my$opacity);     
  96.   ImageDestroy($watermark);
  97.  
  98.   // Записать измененный файл на место
  99.   switch (strtolower($pocket[1])) {
  100.     case "jpeg":
  101.     case "jpg": {
  102.       ImageJPEG($im,$picture,90);
  103.       break;
  104.     }
  105.     case "gif": {
  106.       ImageGIF($im,$picture);
  107.       break;
  108.     }
  109.     case "png": {
  110.       ImagePNG($im,$picture);
  111.       break;
  112.     }
  113.   }
  114.   ImageDestroy($im);
  115.   return true
  116. }
Параметры вызова функции: $picture - полный путь к файлу на сервере, поддерживаются форматы JPG, GIF, PNG. Файл должен быть доступен для записи, так как после нанесения водяного знака он будет перезаписан с тем же именем. $marker - полный путь к файлу водяного знака в формате PNG. $opacity - прозрачность водяного знака в процентах, необязательный параметр, по умолчанию 100%. $watermark_position - положение маркера на картинке, необязательный параметр, по умолчанию правый нижний угол изображения. Доступные значения определены константами, прочие значения игнорируются: 0 - левый нижний угол, 1 - левый верхний угол, 2 - правый нижний угол (значение по умолчанию), 3 - правый верхний угол, 4 - центр изображения.

Пример работы скрипта
Пример работы скрипта

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

Поделиться ссылкой ВКонтакте
Просмотров: 9164 | Комментариев: 13

Метки: PHP, графика
Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
Владимир (09.08.2013 в 23:10):
Возможно ли использовать в качестве водяного знака картинку 32 бит?
alex (24.11.2011 в 19:19):
вот хочу применить данный пример у себя на сайте [del] получиться или нет отпишусь после проверки.
Спасибо.
Игорь (14.07.2011 в 11:03):
ManHunter! Огромное спасибо за понятную и отличноработающую функцию. Отдельное спасибо за дополнение WinkMan`у - очень пригодилось.
Just scripter (04.05.2010 в 01:45):
Каким образом можно наложить прозрачный png на другой прозрачный png?
WinkMan (12.04.2010 в 12:51):
стоит заметит что ImageCopyMerge(...) не видит альфа канал .png
поэтому лучше применить данную функу вызов тот же так что кроме названия ничего менять не придется...
function imagecopymerge_alpha($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct){
    if(!isset($pct)){
        return false;
    }
    $pct /= 100;
    // Get image width and height
    $w = imagesx( $src_im );
    $h = imagesy( $src_im );
    // Turn alpha blending off
    imagealphablending( $src_im, false );
    // Find the most opaque pixel in the image (the one with the smallest alpha value)
    $minalpha = 127;
    for( $x = 0; $x < $w; $x++ )
    for( $y = 0; $y < $h; $y++ ){
        $alpha = ( imagecolorat( $src_im, $x, $y ) >> 24 ) & 0xFF;
        if( $alpha < $minalpha ){
            $minalpha = $alpha;
        }
    }
    //loop through image pixels and modify alpha for each
    for( $x = 0; $x < $w; $x++ ){
        for( $y = 0; $y < $h; $y++ ){
            //get current alpha value (represents the TANSPARENCY!)
            $colorxy = imagecolorat( $src_im, $x, $y );
            $alpha = ( $colorxy >> 24 ) & 0xFF;
            //calculate new alpha
            if( $minalpha !== 127 ){
                $alpha = 127 + 127 * $pct * ( $alpha - 127 ) / ( 127 - $minalpha );
            } else {
                $alpha += 127 * $pct;
            }
            //get the color index with new alpha
            $alphacolorxy = imagecolorallocatealpha( $src_im, ( $colorxy >> 16 ) & 0xFF, ( $colorxy >> 8 ) & 0xFF, $colorxy & 0xFF, $alpha );
            //set pixel with the new color + opacity
            if( !imagesetpixel( $src_im, $x, $y, $alphacolorxy ) ){
                return false;
            }
        }
    }
    // The image copy
    imagecopy($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h);
}
ManHunter (09.02.2010 в 01:12):
Рад что пригодилось, значит не зря старался.
Yagnenok (09.02.2010 в 01:09):
Спасибо за столь прекрасную функцию, все работает отлично !!!!
APTEM (20.08.2009 в 01:30):
Неработает что то :(
Pavel (29.07.2009 в 13:01):
Автору огромное спасибо! Доступно, понятно, надежно!
ManHunter (12.07.2009 в 02:00):
Версия 4.4.9 ничего плохого не сказала, конструкция типа ImagePNG ($im,$picture,5) отработала нормально. Более младшие версии не тестировал.
Nutscracker (12.07.2009 в 01:47):
Да, про поддержку я уже нагуглил:
http://us.php.net/manual/en/fu...imagepng.php
А что старые версии PHP скажут на указание этого параметра (quality)? По идее ведь проигнорировать просто должны.
ManHunter (12.07.2009 в 01:38):
Дефолтный 0, то есть без компрессии. Да и то этот параметр поддерживается только с 5-й версии PHP.
Nutscracker (12.07.2009 в 01:26):
Спасибо, пригодится. :)
А какое по умолчанию сжатие у ImagePNG() ?

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

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.06 сек. / MySQL: 2 (0.0028 сек.) / Память: 4.5 Mb
Наверх