• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JBZoo / Image / 29984857162

20 Jul 2026 09:00PM UTC coverage: 89.643%. Remained the same
29984857162

push

github

web-flow
Merge pull request #33 from JBZoo/release/8.0

8.0.0 — PHP 8.3+ floor & lock-step major

528 of 589 relevant lines covered (89.64%)

100.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.5
/src/Filter.php
1
<?php
2

3
/**
4
 * JBZoo Toolbox - Image.
5
 *
6
 * This file is part of the JBZoo Toolbox project.
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license    MIT
11
 * @copyright  Copyright (C) JBZoo.com, All rights reserved.
12
 * @see        https://github.com/JBZoo/Image
13
 */
14

15
declare(strict_types=1);
16

17
namespace JBZoo\Image;
18

19
use JBZoo\Utils\Filter as VarFilter;
20
use JBZoo\Utils\Image as Helper;
21
use JBZoo\Utils\Vars;
22

23
/**
24
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
25
 */
26
final class Filter
27
{
28
    public const BLUR_SEL  = 0;
29
    public const BLUR_GAUS = 1;
30

31
    private const DEFAULT_BACKGROUND = '#000000';
32
    private const MAX_PERCENT        = 100;
33

34
    /**
35
     * Add sepia effect (emulation).
36
     */
37
    public static function sepia(\GdImage $image): void
38
    {
39
        self::grayscale($image);
6✔
40
        \imagefilter($image, \IMG_FILTER_COLORIZE, 100, 50, 0);
6✔
41
    }
42

43
    /**
44
     * Add grayscale effect.
45
     */
46
    public static function grayscale(\GdImage $image): void
47
    {
48
        \imagefilter($image, \IMG_FILTER_GRAYSCALE);
12✔
49
    }
50

51
    /**
52
     * Pixelate effect.
53
     * @param int $blockSize Size in pixels of each resulting block
54
     */
55
    public static function pixelate(\GdImage $image, int $blockSize = 10): void
56
    {
57
        $blockSize = VarFilter::int($blockSize);
6✔
58
        \imagefilter($image, \IMG_FILTER_PIXELATE, $blockSize);
6✔
59
    }
60

61
    /**
62
     * Edge Detect.
63
     */
64
    public static function edges(\GdImage $image): void
65
    {
66
        \imagefilter($image, \IMG_FILTER_EDGEDETECT);
6✔
67
    }
68

69
    /**
70
     * Emboss.
71
     */
72
    public static function emboss(\GdImage $image): void
73
    {
74
        \imagefilter($image, \IMG_FILTER_EMBOSS);
6✔
75
    }
76

77
    /**
78
     * Negative.
79
     */
80
    public static function invert(\GdImage $image): void
81
    {
82
        \imagefilter($image, \IMG_FILTER_NEGATE);
6✔
83
    }
84

85
    /**
86
     * Blur effect.
87
     * @param int $passes Number of times to apply the filter
88
     * @param int $type   BLUR_SEL|BLUR_GAUS
89
     */
90
    public static function blur(\GdImage $image, int $passes = 1, int $type = self::BLUR_SEL): void
91
    {
92
        $passes = Helper::blur($passes);
12✔
93

94
        $filterType = \IMG_FILTER_SELECTIVE_BLUR;
12✔
95
        if ($type === self::BLUR_GAUS) {
12✔
96
            $filterType = \IMG_FILTER_GAUSSIAN_BLUR;
6✔
97
        }
98

99
        for ($i = 0; $i < $passes; $i++) {
12✔
100
            \imagefilter($image, $filterType);
12✔
101
        }
102
    }
103

104
    /**
105
     * Change brightness.
106
     * @param int $level Darkest = -255, lightest = 255
107
     */
108
    public static function brightness(\GdImage $image, int $level): void
109
    {
110
        \imagefilter($image, \IMG_FILTER_BRIGHTNESS, Helper::brightness($level));
12✔
111
    }
112

113
    /**
114
     * Change contrast.
115
     * @param int $level Min = -100, max = 100
116
     */
117
    public static function contrast(\GdImage $image, int $level): void
118
    {
119
        \imagefilter($image, \IMG_FILTER_CONTRAST, Helper::contrast($level));
6✔
120
    }
121

122
    /**
123
     * @param string $color   Hex color string, array(red, green, blue) or array(red, green, blue, alpha).
124
     *                        Where red, green, blue - integers 0-255, alpha - integer 0-127
125
     * @param float  $opacity 0-100
126
     */
127
    public static function colorize(\GdImage $image, string $color, float $opacity): void
128
    {
129
        $rgba  = Helper::normalizeColor($color);
6✔
130
        $alpha = Helper::opacity2Alpha($opacity);
6✔
131

132
        $red   = Helper::color($rgba[0]);
6✔
133
        $green = Helper::color($rgba[1]);
6✔
134
        $blue  = Helper::color($rgba[2]);
6✔
135

136
        \imagefilter($image, \IMG_FILTER_COLORIZE, $red, $green, $blue, $alpha);
6✔
137
    }
138

139
    /**
140
     * Mean Remove.
141
     */
142
    public static function meanRemove(\GdImage $image): void
143
    {
144
        \imagefilter($image, \IMG_FILTER_MEAN_REMOVAL);
6✔
145
    }
146

147
    /**
148
     * Smooth effect.
149
     * @param int $passes Number of times to apply the filter (1 - 2048)
150
     */
151
    public static function smooth(\GdImage $image, int $passes = 1): void
152
    {
153
        \imagefilter($image, \IMG_FILTER_SMOOTH, Helper::smooth($passes));
6✔
154
    }
155

156
    /**
157
     * Desaturate.
158
     * @param int $percent level of desaturization
159
     */
160
    public static function desaturate(\GdImage $image, int $percent = 100): \GdImage
161
    {
162
        // Determine percentage
163
        $percent = Helper::percent($percent);
12✔
164
        $width   = \imagesx($image);
12✔
165
        $height  = \imagesy($image);
12✔
166

167
        if ($percent === self::MAX_PERCENT) {
12✔
168
            self::grayscale($image);
6✔
169
        } else {
170
            $newImage = \imagecreatetruecolor($width, $height);
6✔
171
            if ($newImage !== false) { // Make a desaturated copy of the image
6✔
172
                \imagealphablending($newImage, false);
6✔
173
                \imagecopy($newImage, $image, 0, 0, 0, 0, $width, $height);
6✔
174
                \imagefilter($newImage, \IMG_FILTER_GRAYSCALE);
6✔
175

176
                // Merge with specified percentage
177
                Helper::imageCopyMergeAlpha(
6✔
178
                    $image,
6✔
179
                    $newImage,
6✔
180
                    [0, 0],
6✔
181
                    [0, 0],
6✔
182
                    [$width, $height],
6✔
183
                    $percent,
6✔
184
                );
6✔
185

186
                return $newImage;
6✔
187
            }
188
            throw new Exception("Can't handle image resource by 'imagecreatetruecolor'");
×
189
        }
190

191
        return $image;
6✔
192
    }
193

194
    /**
195
     * Changes the opacity level of the image.
196
     * @param float|int $opacity 0-1 or 0-100
197
     */
198
    public static function opacity(\GdImage $image, float|int $opacity): \GdImage
199
    {
200
        // Determine opacity
201
        $opacity = Helper::opacity($opacity);
24✔
202

203
        $width  = \imagesx($image);
24✔
204
        $height = \imagesy($image);
24✔
205

206
        $newImage = \imagecreatetruecolor($width, $height);
24✔
207
        if ($newImage !== false) {
24✔
208
            // Set a White & Transparent Background Color
209
            $background = \imagecolorallocatealpha($newImage, 0, 0, 0, 127);
24✔
210
            if ($background !== false) {
24✔
211
                \imagefill($newImage, 0, 0, $background);
24✔
212

213
                // Copy and merge
214
                Helper::imageCopyMergeAlpha(
24✔
215
                    $newImage,
24✔
216
                    $image,
24✔
217
                    [0, 0],
24✔
218
                    [0, 0],
24✔
219
                    [$width, $height],
24✔
220
                    $opacity,
24✔
221
                );
24✔
222

223
                return $newImage;
24✔
224
            }
225

226
            throw new Exception('Image resourced can\'t be handle by "imagecolorallocatealpha"');
×
227
        }
228

229
        throw new Exception('Image resourced can\'t be handle by "imagecreatetruecolor"');
×
230
    }
231

232
    /**
233
     * Rotate an image.
234
     * @param int          $angle   -360 < x < 360
235
     * @param array|string $bgColor Hex color string, array(red, green, blue) or array(red, green, blue,
236
     *                              alpha). Where red, green, blue - integers 0-255, alpha - integer 0-127
237
     */
238
    public static function rotate(
239
        \GdImage $image,
240
        int $angle,
241
        array|string $bgColor = self::DEFAULT_BACKGROUND,
242
    ): \GdImage {
243
        // Perform the rotation
244
        $angle = Helper::rotate($angle);
18✔
245
        $rgba  = Helper::normalizeColor($bgColor);
18✔
246

247
        // @phpstan-ignore-next-line
248
        $newBgColor = (int)\imagecolorallocatealpha($image, $rgba[0], $rgba[1], $rgba[2], $rgba[3]);
18✔
249
        $newImage   = \imagerotate($image, -$angle, $newBgColor);
18✔
250
        if ($newImage === false) {
18✔
251
            throw new Exception("Image can't be rotated");
×
252
        }
253

254
        Helper::addAlpha($newImage);
18✔
255

256
        return $newImage;
18✔
257
    }
258

259
    /**
260
     * Flip an image horizontally or vertically.
261
     *
262
     * @param \GdImage $image     GD resource
263
     * @param string   $direction Direction of flipping - x|y|yx|xy
264
     */
265
    public static function flip(\GdImage $image, string $direction): \GdImage
266
    {
267
        $direction = Helper::direction($direction);
24✔
268

269
        $width  = \imagesx($image);
24✔
270
        $height = \imagesy($image);
24✔
271

272
        $newImage = \imagecreatetruecolor($width, $height);
24✔
273
        if ($newImage !== false) {
24✔
274
            Helper::addAlpha($newImage);
24✔
275

276
            if ($direction === 'y') {
24✔
277
                for ($y = 0; $y < $height; $y++) {
18✔
278
                    \imagecopy($newImage, $image, 0, $y, 0, $height - $y - 1, $width, 1);
18✔
279
                }
280
            } elseif ($direction === 'x') {
18✔
281
                for ($x = 0; $x < $width; $x++) {
18✔
282
                    \imagecopy($newImage, $image, $x, 0, $width - $x - 1, 0, 1, $height);
18✔
283
                }
284
            } elseif ($direction === 'xy' || $direction === 'yx') {
12✔
285
                $newImage = self::flip($image, 'x');
12✔
286
                $newImage = self::flip($newImage, 'y');
12✔
287
            }
288

289
            return $newImage;
24✔
290
        }
291

292
        throw new Exception("Image resource can't be handle by \"imagecreatetruecolor\"");
×
293
    }
294

295
    /**
296
     * Fill image with color.
297
     *
298
     * @param \GdImage     $image GD resource
299
     * @param array|string $color Hex color string, array(red, green, blue) or array(red, green, blue,
300
     *                            alpha). Where red, green, blue - integers 0-255, alpha - integer 0-127
301
     */
302
    public static function fill(\GdImage $image, array|string $color = self::DEFAULT_BACKGROUND): void
303
    {
304
        $width  = \imagesx($image);
6✔
305
        $height = \imagesy($image);
6✔
306

307
        // @phpstan-ignore-next-line
308
        $rgba = Helper::normalizeColor($color);
6✔
309

310
        // @phpstan-ignore-next-line
311
        $fillColor = (int)\imagecolorallocatealpha($image, $rgba[0], $rgba[1], $rgba[2], $rgba[3]);
6✔
312

313
        Helper::addAlpha($image, false);
6✔
314
        \imagefilledrectangle($image, 0, 0, $width, $height, $fillColor);
6✔
315
    }
316

317
    /**
318
     * Add text to an image.
319
     *
320
     * @param \GdImage $image    GD resource
321
     * @param string   $text     Some text to output on image as watermark
322
     * @param string   $fontFile TTF font file path
323
     */
324
    public static function text(\GdImage $image, string $text, string $fontFile, array $params = []): void
325
    {
326
        Text::render($image, $text, $fontFile, $params);
60✔
327
    }
328

329
    /**
330
     * Add border to an image.
331
     * @param array $params Some
332
     */
333
    public static function border(\GdImage $image, array $params = []): void
334
    {
335
        $params = \array_merge([
24✔
336
            'color' => '#333',
24✔
337
            'size'  => 1,
24✔
338
        ], $params);
24✔
339

340
        $size   = Vars::range((int)$params['size'], 1, 1000);
24✔
341
        $rgba   = Helper::normalizeColor((string)$params['color']);
24✔
342
        $width  = \imagesx($image);
24✔
343
        $height = \imagesy($image);
24✔
344

345
        $posX1 = 0;
24✔
346
        $posY1 = 0;
24✔
347
        $posX2 = $width - 1;
24✔
348
        $posY2 = $height - 1;
24✔
349

350
        // @phpstan-ignore-next-line
351
        $color = (int)\imagecolorallocatealpha($image, $rgba[0], $rgba[1], $rgba[2], $rgba[3]);
24✔
352

353
        for ($i = 0; $i < $size; $i++) {
24✔
354
            \imagerectangle($image, $posX1++, $posY1++, $posX2--, $posY2--, $color);
24✔
355
        }
356
    }
357
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc