Passed
Push — master ( 072d4b...7b6e53 )
by Robson
01:41
created

Cropper::fromPng()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 9
nc 1
nop 6
dl 0
loc 14
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
namespace CoffeeCode\Cropper;
4
5
/**
6
 * Class CoffeeCode Thumb
7
 *
8
 * @author Robson V. Leite <https://github.com/robsonvleite>
9
 * @package CoffeeCode\Cropper
10
 */
11
class Cropper
12
{
13
    /** @var string */
14
    private $cachePath;
15
16
    /** @var array */
17
    private $cacheSize;
18
19
    /** @var string */
20
    private $imagePath;
21
22
    /** @var string */
23
    private $imageName;
24
25
    /** @var string */
26
    private $imageMime;
27
28
    /** @var string */
29
    private $imageInfo;
30
31
    /**
32
     * Allow jpg and png to thumb and cache generate
33
     *
34
     * @var array allowed media types
35
     */
36
    private static $allowedExt = ['image/jpeg', "image/png"];
37
38
    /**
39
     * Cropper construct and cache patch
40
     *
41
     * @param string $cachePath
42
     * @param int $jpgQuality
43
     * @param int $pngCompressor
44
     * @return string
45
     */
46
    public function __construct(string $cachePath, int $jpgQuality = 75, int $pngCompressor = 5)
47
    {
48
        $this->cachePath = $cachePath;
49
        $this->cacheSize = [$jpgQuality, $pngCompressor];
50
51
        if (!file_exists($this->cachePath) || !is_dir($this->cachePath)) {
52
            if (!mkdir($this->cachePath, 0755)) {
53
                return "Could not create cache folder";
54
            }
55
        }
56
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type CoffeeCode\Cropper\Cropper which is incompatible with the documented return type string.
Loading history...
57
    }
58
59
    /**
60
     * Make an thumb image
61
     *
62
     * @param string $imagePath
63
     * @param int $width
64
     * @param int|null $height
65
     * @return string
66
     */
67
    function make(string $imagePath, int $width, int $height = null): ?string
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
68
    {
69
        if (!file_exists($imagePath)) {
70
            return "Image not found";
71
        }
72
73
        $this->imagePath = $imagePath;
74
        $this->imageMime = mime_content_type($this->imagePath);
75
        $this->imageInfo = pathinfo($this->imagePath);
76
        $this->imageName = hash("crc32", $this->imageInfo['basename']) . hash("crc32",
77
                "{$width}{$height}") . ($this->imageMime == "image/jpeg" ? ".jpg" : ".png");
78
79
        if (!in_array($this->imageMime, self::$allowedExt)) {
80
            return "Not a valid JPG or PNG image";
81
        }
82
83
        if (file_exists("{$this->cachePath}/{$this->imageName}") && is_file("{$this->cachePath}/{$this->imageName}")) {
84
            return "{$this->cachePath}/{$this->imageName}";
85
        }
86
87
        list($src_w, $src_h) = getimagesize($this->imagePath);
88
        $height = ($height ?? ($width * $src_h) / $src_w);
89
90
        $src_x = 0;
91
        $src_y = 0;
92
93
        $cmp_x = $src_w / $width;
94
        $cmp_y = $src_h / $height;
95
96
        if ($cmp_x > $cmp_y) {
97
            $src_w = round($src_w / $cmp_x * $cmp_y);
98
            $src_x = round(($src_w - ($src_w / $cmp_x * $cmp_y))); //2
99
        } elseif ($cmp_y > $cmp_x) {
100
            $src_h = round($src_h / $cmp_y * $cmp_x);
101
            $src_y = round(($src_h - ($src_h / $cmp_y * $cmp_x))); //2
102
        }
103
104
        if ($this->imageMime == "image/jpeg") {
105
            return $this->fromJpg($width, $height, $src_x, $src_y, $src_w, $src_h);
0 ignored issues
show
Bug introduced by
It seems like $src_x can also be of type double; however, parameter $src_x of CoffeeCode\Cropper\Cropper::fromJpg() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

105
            return $this->fromJpg($width, $height, /** @scrutinizer ignore-type */ $src_x, $src_y, $src_w, $src_h);
Loading history...
Bug introduced by
It seems like $src_y can also be of type double; however, parameter $src_y of CoffeeCode\Cropper\Cropper::fromJpg() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

105
            return $this->fromJpg($width, $height, $src_x, /** @scrutinizer ignore-type */ $src_y, $src_w, $src_h);
Loading history...
106
        }
107
108
        if ($this->imageMime == "image/png") {
109
            return $this->fromPng($width, $height, $src_x, $src_y, $src_w, $src_h);
0 ignored issues
show
Bug introduced by
It seems like $src_x can also be of type double; however, parameter $src_x of CoffeeCode\Cropper\Cropper::fromPng() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

109
            return $this->fromPng($width, $height, /** @scrutinizer ignore-type */ $src_x, $src_y, $src_w, $src_h);
Loading history...
Bug introduced by
It seems like $src_y can also be of type double; however, parameter $src_y of CoffeeCode\Cropper\Cropper::fromPng() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

109
            return $this->fromPng($width, $height, $src_x, /** @scrutinizer ignore-type */ $src_y, $src_w, $src_h);
Loading history...
110
        }
111
112
        return null;
113
    }
114
115
    /**
116
     * Clear cache
117
     *
118
     * @param string|null $imageName
119
     * @example $t->flush("images/image.jpg"); clear image name and variations size
120
     * @example $t->flush(); clear all image cache folder
121
     */
122
    public function flush(string $imageName = null): void
123
    {
124
        $scan = scandir($this->cachePath);
125
        $name = ($imageName ? md5(pathinfo($imageName)['basename']) : null);
126
127
        foreach ($scan as $file) {
128
            $file = "{$this->cachePath}/{$file}";
129
            if ($imageName && strpos($file, $name) && is_file($file)) {
130
                unlink($file);
131
            }
132
133
            if (!$name && is_file($file)) {
134
                unlink($file);
135
            }
136
        }
137
    }
138
139
    /**
140
     * @param int $width
141
     * @param int $height
142
     * @param int $src_x
143
     * @param int $src_y
144
     * @param int $src_w
145
     * @param int $src_h
146
     * @return string
147
     */
148
    private function fromJpg(int $width, int $height, int $src_x, int $src_y, int $src_w, int $src_h): string
149
    {
150
        $thumb = imagecreatetruecolor($width, $height);
151
        $source = imagecreatefromjpeg($this->imagePath);
152
        imagecopyresized($thumb, $source, 0, 0, $src_x, $src_y, $width, $height, $src_w, $src_h);
153
        imagejpeg($thumb, "{$this->cachePath}/{$this->imageName}", $this->cacheSize[0]);
154
155
        imagedestroy($thumb);
156
        imagedestroy($source);
157
158
        return "{$this->cachePath}/{$this->imageName}";
159
    }
160
161
    /**
162
     * @param int $width
163
     * @param int $height
164
     * @param int $src_x
165
     * @param int $src_y
166
     * @param int $src_w
167
     * @param int $src_h
168
     * @return string
169
     */
170
    private function fromPng(int $width, int $height, int $src_x, int $src_y, int $src_w, int $src_h): string
171
    {
172
        $thumb = imagecreatetruecolor($width, $height);
173
        $source = imagecreatefrompng($this->imagePath);
174
175
        imagealphablending($thumb, false);
176
        imagesavealpha($thumb, true);
177
        imagecopyresized($thumb, $source, 0, 0, $src_x, $src_y, $width, $height, $src_w, $src_h);
178
        imagepng($thumb, "{$this->cachePath}/{$this->imageName}", $this->cacheSize[1]);
179
180
        imagedestroy($thumb);
181
        imagedestroy($source);
182
183
        return "{$this->cachePath}/{$this->imageName}";
184
    }
185
}