Водяные знаки (Watermarks) на изображениях используются как для защиты контента от копирования так и для подтверждения авторского права на изображения. Водяные знаки, применяемые для изображений должны быть ненавязчивыми и не должны мешать просмотру самого изображения. В данной статье будет показан один из методов наложения водяного знака, заключающийся в растяжении его по максимуму на все изображение. В качестве основы я буду использовать класс компонента CImageHandler для Yii фреимворка, однако алгоритм наложения, реализованный на PHP с использованием GD, можно адаптировать для других фреимворках или CMS.

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

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

2)Отношение ширины к высоте водяного знака меньше, чем соотношение ширины к высоте изображения. Тут все будет наоборот: водяной знак будет растянут в высоту, и должен быть отцентрирован по ширине.

Для демонстрации выберем второй вариант:

imgwatertest1.jpg

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

watermark.png

Как известно, в CImageHandler уже есть метод watermark для наложения водяного знака, однако в старых он не умел масштабировать водяной знак на всю область изображения. В новой версии вроде как эта возможность появилась, но я её не проверял. Вместо этого я реализовал нужную функциональность в дополнительном методе и назвал его watermark_center_full:

    public function watermark_center_full($watermarkFile) {
        $this->checkLoaded();
        if ($wImg = $this->loadImage($watermarkFile)) {
            $posX = 0;
            $posY = 0;
            $dst_ratio = $this->width / $this->height;
            $water_ratio =  $wImg['width'] / $wImg['height'];
            if ($water_ratio > $dst_ratio){
                $scale = $wImg['width'] / $this->width;
                $posY = $this->height / 2 -  $wImg['height'] / $scale / 2;
            } else {
                $scale = $wImg['height'] / $this->height;
                $posX = $this->width / 2 - $wImg['width'] / $scale / 2;
            }
            imagecopyresized ($this->image, $wImg['image'], $posX, $posY, 0, 0, $wImg['width']/ $scale, $wImg['height']/ $scale, $wImg['width'], $wImg['height']);
            imagedestroy($wImg['image']);
            return $this;
        } else {
            return false;
        }
    }

Использовать метод можно так:

Yii::app()->ih->load($imgPath);
Yii::app()->ih->watermark_center_full($waterMarkPath);
Yii::app()->ih->save($imgPath);

В переменной $imgPath должен быть путь на сервере к исходной картинке, а в переменной $waterMarkPath путь к изображению с водяным знаком(я использовал PNG).

Результат:

imgwatertest1(13).jpg

Ну и первый вариант но уже с прозрачным водяным знаком:

1366x768(4).jpg

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