Добавление водяного знака на изображение в PHP 8
Доброго времени суток! В примере ниже мы рассмотрим с Вами как можно добавить водяной знак на изображение
в PHP. В примере будем использовать библиотеку GD, поэтому она должна быть у Вас установлена. Также в примере
будем использовать версию PHP 8.1.
Класс Image — обертка над GdImage
<?php
declare(strict_types=1);
class Image
{
private string $filename;
private GdImage $image;
private int $width;
private int $height;
private int $bits;
private string $mimeType;
/**
* @throws Exception
*/
public function __construct(string $filename)
{
// если расширение не загружено - бросаем исключение
if (!extension_loaded('gd')) {
throw new Exception('GD extension is not loaded');
}
if (file_exists($filename)) {
$this->filename = $filename;
$fileInfo = getImageSize($filename);
if(!$fileInfo) {
throw new Exception("Image file corrupted: $filename");
}
$this->width = $fileInfo[0];
$this->height = $fileInfo[1];
$this->bits = $fileInfo['bits'] ?? '';
$this->mimeType = $fileInfo['mime'] ?? '';
// выражение match, добавленное в PHP 8, выполняет функции switch
// создаем изображение из файла заданного формата
$this->image = match ($this->mimeType) {
'image/gif' => imageCreateFromGif($filename),
'image/png' => imageCreateFromPng($filename),
'image/jpeg' => imageCreateFromJpeg($filename),
default => throw new Exception("Unrecognized image type: $filename"),
};
} else {
throw new Exception("Could not load image $filename");
}
}
public function getFile(): string
{
return $this->filename;
}
public function getImage(): GdImage
{
return $this->image;
}
public function getResource(): GdImage
{
return $this->image;
}
public function cleanResource(): void
{
imageDestroy($this->image);
}
public function getWidth(): int
{
return $this->width;
}
public function getHeight(): int
{
return $this->height;
}
public function getBits(): int
{
return $this->bits;
}
public function getMime(): string
{
return $this->mime;
}
public function __toString(): string
{
return "[Object Image({$this->getFile()}@{$this->getWidth()}x{$this->getHeight()})]";
}
}
Класс ImageProcessor — принимает класс Image и ставит на нем водяной знак
<?php
declare(strict_types=1);
class ImageProcessor
{
private Image $image;
public function __construct(Image $image)
{
$this->image = $image;
}
/**
* Сохраняет изображение в файл
*
* @throws Exception
*/
public function save(string $file, int $quality = 90): bool
{
$isSaveSuccessfully = false;
$info = pathinfo($file);
$extension = strtolower($info['extension']);
//print($extension);
$image = $this->image->getResource();
$is_resource = is_resource($image);
$isSaveSuccessfully = match ($extension) {
'jpeg', 'jpg' => imageJpeg($image, $file, $quality),
'png' => imagePng($image, $file),
'gif' => imageGif($image, $file),
default => throw new Exception("Unrecognized output image format: $extension"),
};
imageDestroy($image);
return $isSaveSuccessfully;
}
/**
* Возвращает массив из двух точек - положение водяного знака на исходном изображении
*
* @param Image $watermark
* @param WatermarkPosition $position
* @return array<int, int>
*/
private function getIntPosition(Image $watermark, WatermarkPosition $position): array
{
return match ($position) {
WatermarkPosition::TopLeft => [0, 0],
WatermarkPosition::TopCenter => [
($this->image->getWidth() - $watermark->getWidth()) / 2,
0
],
WatermarkPosition::TopRight => [
$this->image->getWidth() - $watermark->getWidth(),
0
],
WatermarkPosition::MiddleLeft => [
0,
($this->image->getHeight()->$watermark->getHeight()) / 2
],
WatermarkPosition::MiddleCenter => [
($this->image->getWidth() - $watermark->getWidth()) / 2,
($this->image->getHeight() - $watermark->getHeight()) / 2
],
WatermarkPosition::MiddleRight => [
$this->image->getWidth() - $watermark->getWidth(),
($this->image->getHeight() - $watermark->getHeight()) / 2
],
WatermarkPosition::BottomLeft => [
0,
$this->image->getHeight() - $watermark->getHeight()
],
WatermarkPosition::BottomCenter => [
($this->image->getWidth() - $watermark->getWidth()) / 2,
$this->image->getHeight() - $watermark->getHeight()
],
WatermarkPosition::BottomRight => [
$this->image->getWidth() - $watermark->getWidth(),
$this->image->getHeight() - $watermark->getHeight()
]
};
}
/**
* Добавляет водяной знак на изображение с помощью функций библиотеки GD
*
* @param Image $watermark
* @param WatermarkPosition $position
* @return void
*
*/
public function addWatermark(Image $watermark, WatermarkPosition $position = WatermarkPosition::BottomRight): void
{
[$watermarkX, $watermarkY] = $this->getIntPosition($watermark, $position);
$image = $this->image->getResource();
ImageAlphaBlending($image, true);
ImageSaveAlpha($image, true);
ImageCopy($image, $watermark->getImage(), intval($watermarkX), intval($watermarkY), 0, 0, $watermark->getWidth(), $watermark->getHeight());
ImageDestroy($watermark->getImage());
$this->image->setGdImage($image);
}
}
Перечисление WatermarkPosition — описывает положения для водяного знака на исходном изображении
<?php
enum WatermarkPosition
{
case TopLeft;
case TopCenter;
case TopRight;
case MiddleLeft;
case MiddleCenter;
case MiddleRight;
case BottomLeft;
case BottomCenter;
case BottomRight;
}
watermark.php — пример использования
<?php
spl_autoload_register(fn($class) => require_once __DIR__ . "/lib/$class.php");
$image1 = 'images/base_image.png';
$image2 = 'images/watermark.png';
try {
$baseImage = new Image($image1);
$watermarkImage = new Image($image2);
$imageProcessor = new ImageProcessor($baseImage);
$imageProcessor->addWatermark($watermarkImage, WatermarkPosition::BottomLeft);
$current_time = time();
$imageProcessor->save("./image_with_watermark_$current_time.jpg");
} catch (Exception $e) {
print($e->getMessage());
}
Таким образом, с помощью PHP библиотеки GD можно ставить водяные знаки на изображении и не только!