Passed
Branch master (aa60db)
by Robson
02:23 queued 57s
created

Thumb::fromJpg()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 7
nc 1
nop 6
dl 0
loc 11
rs 10
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 Thumb
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
     * @param string $cachePath
40
     * @param int $jpgQuality
41
     * @param int $pngCompressor
42
     */
43
    public function __construct(string $cachePath, int $jpgQuality = 75, int $pngCompressor = 5)
44
    {
45
        $this->cachePath = $cachePath;
46
        $this->cacheSize = [$jpgQuality, $pngCompressor];
47
    }
48
49
    /**
50
     * Make an thumb image
51
     *
52
     * @param string $imagePath
53
     * @param int $width
54
     * @param int|null $height
55
     * @return string
56
     * @throws \Exception
57
     */
58
    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...
59
    {
60
        if (!file_exists($imagePath)) {
61
            throw new \Exception("Image not found");
62
        }
63
64
        $this->imagePath = $imagePath;
65
        $this->imageMime = mime_content_type($this->imagePath);
66
        $this->imageInfo = pathinfo($this->imagePath);
67
        $this->imageName = md5($this->imageInfo['basename']) . "x{$width}{$height}" . ($this->imageMime == "image/jpeg" ? ".jpg" : ".png");
68
69
        if (!in_array($this->imageMime, self::$allowedExt)) {
70
            throw new \Exception("Not a valid JPG or PNG image");
71
        }
72
73
        if (!file_exists($this->cachePath) || !is_dir($this->cachePath)) {
74
            if (!mkdir($this->cachePath, 0755)) {
75
                throw new \Exception("Could not create cache folder");
76
            }
77
        }
78
79
        if (file_exists("{$this->cachePath}/{$this->imageName}") && is_file("{$this->cachePath}/{$this->imageName}")) {
80
            return "{$this->cachePath}/{$this->imageName}";
81
        }
82
83
        list($src_w, $src_h) = getimagesize($this->imagePath);
84
        $height = ($height ?? ($width * $src_h) / $src_w);
85
86
        $src_x = 0;
87
        $src_y = 0;
88
89
        $cmp_x = $src_w / $width;
90
        $cmp_y = $src_h / $height;
91
92
        if ($cmp_x > $cmp_y) {
93
            $src_w = round($src_w / $cmp_x * $cmp_y);
94
            $src_x = round(($src_w - ($src_w / $cmp_x * $cmp_y))); //2
95
        } elseif ($cmp_y > $cmp_x) {
96
            $src_h = round($src_h / $cmp_y * $cmp_x);
97
            $src_y = round(($src_h - ($src_h / $cmp_y * $cmp_x))); //2
98
        }
99
100
        if ($this->imageMime == "image/jpeg") {
101
            return $this->fromJpg($width, $height, $src_x, $src_y, $src_w, $src_h);
0 ignored issues
show
Bug introduced by
It seems like $src_y can also be of type double; however, parameter $src_y of CoffeeCode\Cropper\Thumb::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

101
            return $this->fromJpg($width, $height, $src_x, /** @scrutinizer ignore-type */ $src_y, $src_w, $src_h);
Loading history...
Bug introduced by
It seems like $src_x can also be of type double; however, parameter $src_x of CoffeeCode\Cropper\Thumb::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

101
            return $this->fromJpg($width, $height, /** @scrutinizer ignore-type */ $src_x, $src_y, $src_w, $src_h);
Loading history...
102
        }
103
104
        if ($this->imageMime == "image/png") {
105
            return $this->fromPng($width, $height, $src_x, $src_y, $src_w, $src_h);
0 ignored issues
show
Bug introduced by
It seems like $src_y can also be of type double; however, parameter $src_y of CoffeeCode\Cropper\Thumb::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

105
            return $this->fromPng($width, $height, $src_x, /** @scrutinizer ignore-type */ $src_y, $src_w, $src_h);
Loading history...
Bug introduced by
It seems like $src_x can also be of type double; however, parameter $src_x of CoffeeCode\Cropper\Thumb::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

105
            return $this->fromPng($width, $height, /** @scrutinizer ignore-type */ $src_x, $src_y, $src_w, $src_h);
Loading history...
106
        }
0 ignored issues
show
Bug Best Practice introduced by
The function implicitly returns null when the if condition on line 104 is false. This is incompatible with the type-hinted return string. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

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