Issues (11)

app/Image/LayerValidator.php (1 issue)

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Minepic\Image;
6
7
use Minepic\Image\Components\Side;
8
use Minepic\Image\Exceptions\ImageTrueColorCreationFailedException;
9
10
class LayerValidator
11
{
12
    /**
13
     * Max Standard Deviation value for layer check.
14
     */
15
    private const DEFAULT_STANDARD_DEVIATION = 0.2;
16
    private int $meanAlpha;
17
    private float $redStdDev;
18
    private float $greenStdDev;
19
    private float $blueStdDev;
20
21
    /**
22
     * Checks if base image has helm for section.
23
     *
24
     * @throws ImageTrueColorCreationFailedException
25
     */
26
    public function check(\GdImage $sourceImage, Side $side): bool
27
    {
28
        $checkImage = $this->createCheckImage($sourceImage, $side);
29
        $this->calculate($checkImage, $side);
30
31
        return $this->validStdDev() || $this->meanAlpha === 127;
32
    }
33
34
    /**
35
     * Calculate sttdev for merging helm.
36
     */
37
    protected function calculate(\GdImage $checkImage, Side $side): void
38
    {
39
        // Check for helm image
40
        $allRed = [];
41
        $allGreen = [];
42
        $allBlue = [];
43
        $allAlpha = [];
44
        $x = 0;
45
        while ($x < $side->getWidth()) {
46
            $y = 0;
47
            while ($y < $side->getHeight()) {
48
                $color = (int) imagecolorat($checkImage, $x, $y);
49
                $colors = imagecolorsforindex($checkImage, $color);
50
                $allRed[] = $colors['red'];
51
                $allGreen[] = $colors['green'];
52
                $allBlue[] = $colors['blue'];
53
                $allAlpha[] = $colors['alpha'];
54
                ++$y;
55
            }
56
            ++$x;
57
        }
58
        // mean value for each color
59
        $totalPixels = $side->getWidth() * $side->getHeight();
60
        $meanRed = array_sum($allRed) / $totalPixels;
61
        $meanGreen = array_sum($allGreen) / $totalPixels;
62
        $meanBlue = array_sum($allBlue) / $totalPixels;
63
        $this->meanAlpha = (int) round(array_sum($allAlpha) / $totalPixels);
64
        // Arrays deviation
65
        $devsRed = [];
66
        $devsGreen = [];
67
        $devsBlue = [];
68
        $i = 0;
69
        while ($i < $totalPixels) {
70
            $devsRed[] = ($allRed[$i] - $meanRed) ** 2;
71
            $devsGreen[] = ($allGreen[$i] - $meanGreen) ** 2;
72
            $devsBlue[] = ($allBlue[$i] - $meanBlue) ** 2;
73
            ++$i;
74
        }
75
        // stddev for each color
76
        $this->redStdDev = sqrt(array_sum($devsRed) / $totalPixels);
77
        $this->greenStdDev = sqrt(array_sum($devsGreen) / $totalPixels);
78
        $this->blueStdDev = sqrt(array_sum($devsBlue) / $totalPixels);
79
    }
80
81
    /**
82
     * @throws ImageTrueColorCreationFailedException
83
     */
84
    private function createCheckImage(\GdImage $sourceImage, Side $side): \GdImage
85
    {
86
        $width = $side->getWidth();
87
        $height = $side->getHeight();
88
        $checkImage = imagecreatetruecolor($side->getWidth(), $side->getHeight());
89
        if ($checkImage === false) {
90
            throw new ImageTrueColorCreationFailedException('imagecreatetruecolor failed');
91
        }
92
        imagealphablending($checkImage, false);
93
        imagesavealpha($checkImage, true);
94
        $colorIdentifier = (int) imagecolorallocatealpha($checkImage, 255, 255, 255, 127);
95
        imagefilledrectangle($checkImage, 0, 0, $width, $height, $colorIdentifier);
96
        imagecopy($checkImage, $sourceImage, 0, 0, $side->getTopLeft()->getX(), $side->getTopLeft()->getY(), $width, $height);
97
98
        return $checkImage;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $checkImage could return the type resource which is incompatible with the type-hinted return GdImage. Consider adding an additional type-check to rule them out.
Loading history...
99
    }
100
101
    private function validStdDev(): bool
102
    {
103
        return ($this->redStdDev > self::DEFAULT_STANDARD_DEVIATION && $this->greenStdDev > self::DEFAULT_STANDARD_DEVIATION) ||
104
            ($this->redStdDev > self::DEFAULT_STANDARD_DEVIATION && $this->blueStdDev > self::DEFAULT_STANDARD_DEVIATION) ||
105
            ($this->greenStdDev > self::DEFAULT_STANDARD_DEVIATION && $this->blueStdDev > self::DEFAULT_STANDARD_DEVIATION);
106
    }
107
}
108