Test Failed
Push — master ( 930d65...56c331 )
by Kanstantsin
06:10 queued 28s
created

Image::createBox()   D

Complexity

Conditions 9
Paths 6

Size

Total Lines 27
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
cc 9
eloc 14
nc 6
nop 1
dl 0
loc 27
ccs 0
cts 9
cp 0
crap 90
rs 4.909
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace tkanstantsin\fileupload\formatter;
5
6
use Imagine\Image\Box;
7
use Imagine\Image\BoxInterface;
8
use Imagine\Image\ImageInterface;
9
use Imagine\Image\Palette\RGB as RGBPalette;
10
use Imagine\Image\Point;
11
use Imagine\Imagick\Imagine;
12
13
/**
14
 * Class ImageProcessor
15
 */
16
class Image extends File
17
{
18
    /**
19
     * Like background `cover` in css.
20
     */
21
    public const RESIZE_OUTBOUND = \Imagine\Image\ImageInterface::THUMBNAIL_OUTBOUND;
22
    /**
23
     * Like background `contain` in css.
24
     */
25
    public const RESIZE_INSET = \Imagine\Image\ImageInterface::THUMBNAIL_INSET;
26
    /**
27
     * Means that image may be smaller than defined in config, never bigger.
28
     */
29
    public const RESIZE_INSET_KEEP_RATIO = 'inset_keep_ratio';
30
31
    public const DEFAULT_EXTENSION = 'jpg';
32
33
    /**
34
     * @var int
35
     */
36
    public $width;
37
    /**
38
     * @var int
39
     */
40
    public $height;
41
42
    /**
43
     * Used when defined only height as upper limit for width
44
     * @todo: implement in Image::createBox() method.
45
     * @var int
46
     */
47
    public $maxWidth;
48
    /**
49
     * Used when defined only widith as upper limit for height
50
     * @var int
51
     */
52
    public $maxHeight;
53
54
    /**
55
     * Used for jpg images which may be png originally and have transparency.
56
     * @var string
57
     */
58
    public $transparentBackground = 'ffffff';
59
60
    /**
61
     * @var string
62
     */
63
    public $mode = self::RESIZE_INSET;
64
    /**
65
     * Whether image must keep aspect ration when used inset mote.
66
     * Means that image would may be smaller than smaller
67
     * @var bool
68
     */
69
    public $keepRatio = true;
70
71
    /**
72
     * @var Imagine
73
     */
74
    protected $imagine;
75
76
    /**
77
     * @inheritdoc
78
     * @throws \UnexpectedValueException
79
     * @throws \Imagine\Exception\InvalidArgumentException
80
     * @throws \Imagine\Exception\RuntimeException
81
     */
82
    protected function getContentInternal()
83
    {
84
        $this->imagine = new Imagine();
85
        $image = $this->imagine->read(parent::getContentInternal());
86
        $image = $this->format($image);
87
88
        $extension = mb_strtolower($this->file->getExtension() ?? self::DEFAULT_EXTENSION);
89
        if (\in_array($extension, ['jpg', 'jpeg'], true)) {
90
            $image = $this->setBackgroundInsteadOfAlpha($image);
91
        }
92
93
        return $image->get($extension);
94
    }
95
96
    /**
97
     * @param ImageInterface $image
98
     * @return ImageInterface
99
     * @throws \UnexpectedValueException
100
     * @throws \Imagine\Exception\RuntimeException
101
     * @throws \Imagine\Exception\InvalidArgumentException
102
     */
103
    protected function format(ImageInterface $image): ImageInterface
104
    {
105
        $box = $this->createBox($image->getSize());
106
        if ($box === null) {
107
            return $image;
108
        }
109
110
        switch ($this->mode) {
111
            case self::RESIZE_OUTBOUND:
112
            case self::RESIZE_INSET:
113
                return $image->thumbnail($box, $this->mode);
114
            case self::RESIZE_INSET_KEEP_RATIO:
115
                // TODO: implement new resize mode.
116
                throw new \UnexpectedValueException(sprintf('Resize mode `%s` not supported yet', $this->mode));
117
            default:
118
                throw new \UnexpectedValueException(sprintf('Image resize mode `%s` not defined', $this->mode));
119
        }
120
    }
121
122
    /**
123
     * Add Image::transparentBackground color behind image.
124
     * If original image was of PNG type but stored with jpg extension, or it
125
     * must be converted
126
     *
127
     * @param ImageInterface $image
128
     * @return ImageInterface
129
     * @throws \Imagine\Exception\RuntimeException
130
     * @throws \Imagine\Exception\InvalidArgumentException
131
     */
132
    protected function setBackgroundInsteadOfAlpha(ImageInterface $image): ImageInterface
133
    {
134
        $palette = new RGBPalette();
135
        $backgroundColor = $palette->color($this->transparentBackground, 100);
136
        $background = $this->imagine->create($image->getSize(), $backgroundColor);
137
138
        return $background->paste($image, new Point(0, 0));
139
    }
140
141
    /**
142
     * @param BoxInterface $actualBox
143
     * @return BoxInterface|null
144
     * @throws \Imagine\Exception\InvalidArgumentException
145
     */
146
    protected function createBox(BoxInterface $actualBox): ?BoxInterface
147
    {
148
        if ($this->width !== null
149
            && $this->height !== null
150
        ) {
151
            return new Box($this->width, $this->height);
152
        }
153
154
        if ($this->width !== null) {
155
            $box = $actualBox->widen($this->width);
156
            if ($this->maxHeight !== null && $this->maxHeight < $box->getHeight()) {
157
                $box = $box->heighten($this->maxHeight);
158
            }
159
160
            return $box;
161
        }
162
        if ($this->height !== null) {
163
            $box = $actualBox->heighten($this->height);
164
            if ($this->maxWidth !== null && $this->maxWidth < $box->getWidth()) {
165
                $box = $box->heighten($this->maxWidth);
166
            }
167
168
            return $box;
169
        }
170
171
        // both are null
172
        return null;
173
    }
174
}