Completed
Push — CheeseSucker-patch-1 ( c299a1 )
by Julien
57s
created

CropFace::setMaxExecutionTime()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace stojg\crop;
4
5
/**
6
 * CropFace
7
 *
8
 * This class will try to find the most interesting point in the image by trying to find a face and
9
 * center the crop on that
10
 *
11
 * @todo implement
12
 * @see https://github.com/mauricesvay/php-facedetection/blob/master/FaceDetector.php
13
 */
14
class CropFace extends CropEntropy
15
{
16
    const CLASSIFIER_FACE = '/classifier/haarcascade_frontalface_default.xml';
17
    const CLASSIFIER_PROFILE = '/classifier/haarcascade_profileface.xml';
18
19
    /**
20
     * imagePath original image path
21
     *
22
     * @var mixed
23
     * @access protected
24
     */
25
    protected $imagePath;
26
27
    /**
28
     * safeZoneList
29
     *
30
     * @var array
31
     * @access protected
32
     */
33
    protected $safeZoneList;
34
35
    /**
36
     * max execution time (in seconds)
37
     *
38
     * @var int
39
     * @access protected
40
     */
41
    protected $maxExecutionTime;
42
43
    /**
44
     *
45
     * @param string $imagePath
46
     */
47
    public function __construct($imagePath)
48
    {
49
        $this->imagePath = $imagePath;
50
        parent::__construct($imagePath);
51
    }
52
53
    /**
54
     * setMaxExecutionTime
55
     *
56
     * @param int $maxExecutionTime max execution time (in sec)
57
     * @access public
58
     * @return void
59
     */
60
    public function setMaxExecutionTime($maxExecutionTime)
61
    {
62
        $this->maxExecutionTime = $maxExecutionTime;
63
    }
64
65
    /**
66
     * getFaceList get faces positions and sizes
67
     *
68
     * @access protected
69
     * @return array
70
     */
71
    protected function getFaceList()
72
    {
73
        if (!function_exists('face_detect')) {
74
            $msg = 'PHP Facedetect extension must be installed.
75
                    See http://www.xarg.org/project/php-facedetect/ for more details';
76
            throw new \Exception($msg);
77
        }
78
79
        if ($this->maxExecutionTime) {
80
            $timeBefore = microtime(true);
81
        }
82
        $faceList = $this->getFaceListFromClassifier(self::CLASSIFIER_FACE);
83
        if ($this->maxExecutionTime) {
84
            $timeSpent = microtime(true) - $timeBefore;
0 ignored issues
show
Bug introduced by
The variable $timeBefore does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
85
        }
86
87
        if (!$this->maxExecutionTime || $timeSpent < ($this->maxExecutionTime / 2)) {
0 ignored issues
show
Bug introduced by
The variable $timeSpent does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
88
            $profileList = $this->getFaceListFromClassifier(self::CLASSIFIER_PROFILE);
89
            $faceList = array_merge($faceList, $profileList);
90
        }
91
92
        return $faceList;
93
    }
94
95
    /**
96
     * getFaceListFromClassifier
97
     *
98
     * @param string $classifier
99
     * @access protected
100
     * @return array
101
     */
102
    protected function getFaceListFromClassifier($classifier)
103
    {
104
        $faceList = face_detect($this->imagePath, __DIR__ . $classifier);
105
        if (!$faceList) {
106
            $faceList = array();
107
        }
108
109
        return $faceList;
110
    }
111
112
    /**
113
     * getSafeZoneList
114
     *
115
     * @access private
116
     * @return array
117
     */
118
    protected function getSafeZoneList()
119
    {
120
        if (!isset($this->safeZoneList)) {
121
            $this->safeZoneList = array();
122
        }
123
        // the local key is the current image width-height
124
        $key = $this->originalImage->getImageWidth() . '-' . $this->originalImage->getImageHeight();
125
126
        if (!isset($this->safeZoneList[$key])) {
127
            $faceList = $this->getFaceList();
128
129
            // getFaceList works on the main image, so we use a ratio between main/current image
130
            $xRatio = $this->getBaseDimension('width') / $this->originalImage->getImageWidth();
131
            $yRatio = $this->getBaseDimension('height') / $this->originalImage->getImageHeight();
132
133
            $safeZoneList = array();
134
            foreach ($faceList as $face) {
135
                $hw = ceil($face['w'] / 2);
136
                $hh = ceil($face['h'] / 2);
137
                $safeZone = array(
138
                    'left' => $face['x'] - $hw,
139
                    'right' => $face['x'] + $face['w'] + $hw,
140
                    'top' => $face['y'] - $hh,
141
                    'bottom' => $face['y'] + $face['h'] + $hh
142
                );
143
144
                $safeZoneList[] = array(
145
                    'left' => round($safeZone['left'] / $xRatio),
146
                    'right' => round($safeZone['right'] / $xRatio),
147
                    'top' => round($safeZone['top'] / $yRatio),
148
                    'bottom' => round($safeZone['bottom'] / $yRatio),
149
                );
150
            }
151
            $this->safeZoneList[$key] = $safeZoneList;
152
        }
153
154
        return $this->safeZoneList[$key];
155
    }
156
}
157