Completed
Push — master ( bcf055...f94c59 )
by Kanstantsin
02:59
created

Watermark::getPositionPoint()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 5
ccs 0
cts 5
cp 0
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace tkanstantsin\fileupload\formatter\adapter;
5
6
use Imagine\Image\BoxInterface;
7
use Imagine\Image\ImageInterface;
8
use Imagine\Image\Point;
9
use Imagine\Imagick\Imagine;
10
use tkanstantsin\fileupload\config\InvalidConfigException;
11
use tkanstantsin\fileupload\formatter\Image;
12
use tkanstantsin\fileupload\model\BaseObject;
13
use tkanstantsin\fileupload\model\IFile;
14
15
/**
16
 * Class Watermark
17
 */
18
class Watermark extends BaseObject implements IFormatAdapter
19
{
20
    public const POSITION_CENTER_CENTER = 'center_center';
21
    public const POSITION_CENTER_LEFT = 'center_left';
22
    public const POSITION_CENTER_RIGHT = 'center_right';
23
    public const POSITION_TOP_CENTER = 'top_center';
24
    public const POSITION_TOP_LEFT = 'top_left';
25
    public const POSITION_TOP_RIGHT = 'top_right';
26
    public const POSITION_BOTTOM_CENTER = 'bottom_center';
27
    public const POSITION_BOTTOM_LEFT = 'bottom_left';
28
    public const POSITION_BOTTOM_RIGHT = 'bottom_right';
29
30
    public const SIZE_COVER = 'cover';
31
    public const SIZE_CONTAIN = 'contain';
32
    public const SIZE_STRETCH = 'stretch';
33
34
    /**
35
     * Absolute path to image file
36
     * @var string|null
37
     */
38
    public $markFilepath;
39
    /**
40
     * Water mark image binary
41
     * @var string|resource|null
42
     */
43
    public $markContent;
44
45
    /**
46
     * Opacity for watermark image
47
     * @var int
48
     */
49
    public $opacity = 100;
50
    /**
51
     * TODO: implement position.
52
     * @var string
53
     */
54
    public $position = self::POSITION_CENTER_CENTER;
55
    /**
56
     * TODO: implement size.
57
     * @var string
58
     */
59
    public $size = self::SIZE_CONTAIN;
60
    /**
61
     * Watermark size relative to image size
62
     * @var float
63
     */
64
    public $scale = 0.9;
65
66
    /**
67
     * @inheritdoc
68
     * @throws \tkanstantsin\fileupload\config\InvalidConfigException
69
     */
70
    public function init(): void
71
    {
72
        parent::init();
73
74
        if ($this->scale > 1 || $this->scale <= 0) {
75
            throw new InvalidConfigException('Scale must be greater than 0 and lower or equal than 1.');
76
        }
77
        if ($this->markFilepath === null && $this->markContent === null) {
78
            throw new InvalidConfigException('Either watermarkPath or watermarkImage must be defined.');
79
        }
80
        if ($this->markFilepath !== null && !file_exists($this->markFilepath)) {
81
            throw new InvalidConfigException(sprintf('Watermark by path `%s` not found.', $this->markFilepath));
82
        }
83
    }
84
85
    /**
86
     * Applies filters or something to content and return it
87
     *
88
     * @param IFile $file
89
     * @param       $content
90
     *
91
     * @return mixed
92
     * @throws \UnexpectedValueException
93
     * @throws \Imagine\Exception\InvalidArgumentException
94
     * @throws \Imagine\Exception\RuntimeException
95
     * @throws \ImageOptimizer\Exception\Exception
96
     */
97
    public function exec(IFile $file, $content)
98
    {
99
        $imagine = new Imagine();
100
101
        $image = \is_resource($content)
102
            ? $imagine->read($content)
103
            : $imagine->load($content);
104
        $imageSize = $image->getSize();
105
106
        $watermark = $this->getWatermark($imagine);
107
        $watermarkSize = $watermark->getSize();
108
109
        // NOTE: only for position: center
110
        $watermarkSize = $this->getWatermarkBox($imageSize, $watermarkSize);
111
112
        /* @see http://urmaul.com/blog/imagick-filters-comparison */
113
        $watermark = $watermark->resize($watermarkSize, ImageInterface::FILTER_SINC);
114
        $watermarkSize = $watermark->getSize();
115
116
        $image = $image->paste($watermark, $this->getPositionPoint($imageSize, $watermarkSize));
117
118
        return $image->get($file->getExtension() ?? Image::DEFAULT_EXTENSION);
119
    }
120
121
    /**
122
     * Get watermark image
123
     * @param Imagine $imagine
124
     * @return ImageInterface
125
     * @throws \Imagine\Exception\RuntimeException
126
     * @throws \UnexpectedValueException
127
     */
128
    private function getWatermark(Imagine $imagine): ImageInterface
129
    {
130
        $resource = null;
131
        if ($this->markFilepath !== null) {
132
            $resource = fopen($this->markFilepath, 'rb');
133
        } elseif (\is_string($this->markContent)) {
134
            $resource = 'a'; // TODO: create resource.
135
        } elseif (\is_resource($this->markContent)) {
136
            $resource = $this->markContent;
137
        }
138
139
        if ($resource === null) {
140
            throw new \UnexpectedValueException('Water mark image invalid format');
141
        }
142
143
        return $imagine->read($resource);
144
    }
145
146
    /**
147
     * @param BoxInterface $imageSize
148
     * @param BoxInterface $watermarkSize
149
     *
150
     * @return BoxInterface
151
     */
152
    private function getWatermarkBox(BoxInterface $imageSize, BoxInterface $watermarkSize): BoxInterface
153
    {
154
        // ensure that watermark smaller than image
155
        $watermarkSize = $watermarkSize->widen($imageSize->getWidth() * $this->scale);
0 ignored issues
show
Bug introduced by
$imageSize->getWidth() * $this->scale of type double is incompatible with the type integer expected by parameter $width of Imagine\Image\BoxInterface::widen(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

155
        $watermarkSize = $watermarkSize->widen(/** @scrutinizer ignore-type */ $imageSize->getWidth() * $this->scale);
Loading history...
156
        $watermarkSize = $watermarkSize->heighten(min($watermarkSize->getHeight(), $imageSize->getHeight()));
157
158
        return $watermarkSize;
159
    }
160
161
    /**
162
     * @param BoxInterface $imageSize
163
     * @param BoxInterface $watermarkSize
164
     *
165
     * @return Point
166
     * @throws \Imagine\Exception\InvalidArgumentException
167
     */
168
    private function getPositionPoint(BoxInterface $imageSize, BoxInterface $watermarkSize): Point
169
    {
170
        return new Point(
171
            ($imageSize->getWidth() - $watermarkSize->getWidth()) / 2,
172
            ($imageSize->getHeight() - $watermarkSize->getHeight()) / 2
173
        );
174
    }
175
}