Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 41 |
|
0.00% |
0 / 1 |
CRAP | |
0.00% |
0 / 1 |
Kernel | |
0.00% |
0 / 41 |
|
0.00% |
0 / 1 |
182 | |
0.00% |
0 / 1 |
convolve | |
0.00% |
0 / 41 |
|
0.00% |
0 / 1 |
182 |
1 | <?php |
2 | /** |
3 | * Jingga |
4 | * |
5 | * PHP Version 8.1 |
6 | * |
7 | * @package phpOMS\Image |
8 | * @copyright Dennis Eichhorn |
9 | * @license OMS License 2.0 |
10 | * @version 1.0.0 |
11 | * @link https://jingga.app |
12 | */ |
13 | declare(strict_types=1); |
14 | |
15 | namespace phpOMS\Image; |
16 | |
17 | use phpOMS\Utils\NumericUtils; |
18 | |
19 | /** |
20 | * Kernel - image sharpening/blurring |
21 | * |
22 | * @package phpOMS\Image |
23 | * @license OMS License 2.0 |
24 | * @link https://jingga.app |
25 | * @since 1.0.0 |
26 | */ |
27 | final class Kernel |
28 | { |
29 | public const KERNEL_RIDGE_1 = [ |
30 | [0, -1, 0], |
31 | [-1, 4, -1], |
32 | [0, -1, 0], |
33 | ]; |
34 | |
35 | public const KERNEL_RIDGE_2 = [ |
36 | [-1, -1, -1], |
37 | [-1, 8, -1], |
38 | [-1, -1, -1], |
39 | ]; |
40 | |
41 | public const KERNEL_SHARPEN = [ |
42 | [0, -1, 0], |
43 | [-1, 5, -1], |
44 | [0, -1, 0], |
45 | ]; |
46 | |
47 | public const KERNEL_BOX_BLUR = [ |
48 | [1 / 9, 1 / 9, 1 / 9], |
49 | [1 / 9, 1 / 9, 1 / 9], |
50 | [1 / 9, 1 / 9, 1 / 9], |
51 | ]; |
52 | |
53 | public const KERNEL_GAUSSUAN_BLUR_3 = [ |
54 | [1 / 16, 2 / 16, 1 / 16], |
55 | [2 / 16, 4 / 16, 2 / 16], |
56 | [1 / 16, 2 / 16, 1 / 16], |
57 | ]; |
58 | |
59 | public const KERNEL_EMBOSS = [ |
60 | [-2, -1, 0], |
61 | [-1, 1, 1], |
62 | [0, 1, 2], |
63 | ]; |
64 | |
65 | public const KERNEL_UNSHARP_MASKING = [ |
66 | [-1 / 256, -4 / 256, -6 / 256, -4 / 256, -1 / 256], |
67 | [-4 / 256, -16 / 256, -24 / 256, -16 / 256, -4 / 256], |
68 | [-6 / 256, -24 / 256, 476 / 256, -24 / 256, -6 / 256], |
69 | [-4 / 256, -16 / 256, -24 / 256, -16 / 256, -4 / 256], |
70 | [-1 / 256, -4 / 256, -6 / 256, -4 / 256, -1 / 256], |
71 | ]; |
72 | |
73 | /** |
74 | * @see https://en.wikipedia.org/wiki/Kernel_(image_processing) |
75 | * @see https://towardsdatascience.com/image-processing-with-python-blurring-and-sharpening-for-beginners-3bcebec0583a |
76 | * @see https://web.eecs.umich.edu/~jjcorso/t/598F14/files/lecture_0924_filtering.pdf |
77 | */ |
78 | public static function convolve(string $inPath, string $outPath, array $kernel) : void |
79 | { |
80 | $im = null; |
81 | if (\strripos($inPath, 'png') !== false) { |
82 | $im = \imagecreatefrompng($inPath); |
83 | } elseif (\strripos($inPath, 'jpg') !== false || \strripos($inPath, 'jpeg') !== false) { |
84 | $im = \imagecreatefromjpeg($inPath); |
85 | } else { |
86 | $im = \imagecreatefromgif($inPath); |
87 | } |
88 | |
89 | if ($im === false) { |
90 | return; |
91 | } |
92 | |
93 | if (\count($kernel) === 3) { |
94 | \imageconvolution($im, $kernel, 1, 0); |
95 | } else { |
96 | $dim = [\imagesx($im), \imagesy($im)]; |
97 | $kDim = [\count($kernel[1]), \count($kernel)]; |
98 | |
99 | $kWidthRadius = NumericUtils::uRightShift($kDim[0], 1); |
100 | $kHeightRadius = NumericUtils::uRightShift($kDim[1], 1); |
101 | |
102 | for ($y = 0; $y < $dim[1]; ++$y) { |
103 | for ($x = 0; $x < $dim[0]; ++$x) { |
104 | $newR = 0; |
105 | $newG = 0; |
106 | $newB = 0; |
107 | |
108 | for ($ky = 0; $ky < $kDim[0]; ++$ky) { |
109 | for ($kx = 0; $kx < $kDim[1]; ++$kx) { |
110 | $pixel = \imagecolorat($im, |
111 | \min(\max($x + $kx - $kWidthRadius, 0), $dim[0] - 1), |
112 | \min(\max($y + $ky - $kHeightRadius, 0), $dim[1] - 1) |
113 | ); |
114 | |
115 | // old |
116 | $r = ($pixel >> 16) & 0xFF; |
117 | $g = ($pixel >> 8) & 0xFF; |
118 | $b = $pixel & 0xFF; |
119 | |
120 | // new |
121 | $newR += $r * $kernel[$ky][$kx]; |
122 | $newG += $g * $kernel[$ky][$kx]; |
123 | $newB += $b * $kernel[$ky][$kx]; |
124 | } |
125 | } |
126 | |
127 | $newR = (int) \max(0, \min(255, $newR)); |
128 | $newG = (int) \max(0, \min(255, $newG)); |
129 | $newB = (int) \max(0, \min(255, $newB)); |
130 | |
131 | \imagesetpixel($im, $x, $y, (int) (($newR << 16) | ($newG << 8) | $newB)); |
132 | } |
133 | } |
134 | } |
135 | |
136 | if (\strripos($outPath, 'png') !== false) { |
137 | \imagepng($im, $outPath); |
138 | } elseif (\strripos($outPath, 'jpg') !== false || \strripos($outPath, 'jpeg') !== false) { |
139 | \imagejpeg($im, $outPath); |
140 | } else { |
141 | \imagegif($im, $outPath); |
142 | } |
143 | |
144 | \imagedestroy($im); |
145 | } |
146 | } |