Completed
Push — master ( b99dd2...fc7346 )
by Oscar
10s
created

Face::getOffsets()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 9
rs 9.6666
cc 1
eloc 6
nc 1
nop 3
1
<?php
2
3
namespace Imagecow\Crops;
4
5
use Imagick;
6
use Imagecow\ImageException;
7
8
/**
9
 * This class is adapted from Stig Lindqvist's great Crop library:
10
 * https://github.com/stojg/crop
11
 * Copyright (c) 2013, Stig Lindqvist.
12
 *
13
 * CropFace
14
 *
15
 * This class will try to find the most interesting point in the image by trying to find a face and
16
 * center the crop on that
17
 *
18
 * @todo implement
19
 * @see https://github.com/mauricesvay/php-facedetection/blob/master/FaceDetector.php
20
 */
21
class Face extends Entropy
22
{
23
    const CLASSIFIER_FACE = '/classifier/haarcascade_frontalface_default.xml';
24
    const CLASSIFIER_PROFILE = '/classifier/haarcascade_profileface.xml';
25
26
    /**
27
     * safeZoneList
28
     *
29
     * @var array
30
     * @access protected
31
     */
32
    protected static $safeZoneList;
33
34
    /**
35
     * originalImage
36
     *
37
     * @var array
38
     * @access protected
39
     */
40
    protected static $originalImage;
41
42
    /**
43
     * baseDimension
44
     *
45
     * @var array
46
     * @access protected
47
     */
48
    protected static $baseDimension;
49
50
    /**
51
     * Returns the x,y values.
52
     *
53
     * @param Imagick $original
54
     * @param int     $targetWidth
55
     * @param int     $targetHeight
56
     *
57
     * @return array
58
     */
59
    public static function getOffsets(Imagick $original, $targetWidth, $targetHeight)
60
    {
61
        static::$originalImage = $original;
0 ignored issues
show
Documentation Bug introduced by
It seems like $original of type object<Imagick> is incompatible with the declared type array of property $originalImage.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
62
        static::$baseDimension = [
63
            'width' => $original->getImageWidth(),
64
            'height' => $original->getImageWidth(),
65
        ];
66
        parent::getOffsets($original, $targetWidth, $targetHeight);
67
    }
68
69
    /**
70
     * getBaseDimension
71
     *
72
     * @param string $key width|height
73
     * @access protected
74
     * @return int
75
     */
76
    protected static function getBaseDimension($key)
77
    {
78
        if (isset(static::$baseDimension)) {
79
            return static::$baseDimension[$key];
80
        } elseif ($key == 'width') {
81
            return static::$originalImage->getImageWidth();
0 ignored issues
show
Bug introduced by
The method getImageWidth cannot be called on static::$originalImage (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
82
        } else {
83
            return static::$originalImage->getImageHeight();
0 ignored issues
show
Bug introduced by
The method getImageHeight cannot be called on static::$originalImage (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
84
        }
85
    }
86
87
    /**
88
     * getFaceList get faces positions and sizes
89
     *
90
     * @access protected
91
     * @return array
92
     */
93
    protected static function getFaceList()
94
    {
95
        if (!function_exists('face_detect')) {
96
            $msg = 'PHP Facedetect extension must be installed.
97
                    See http://www.xarg.org/project/php-facedetect/ for more details';
98
            throw new ImageException($msg);
99
        }
100
101
        $faceList = static::getFaceListFromClassifier(self::CLASSIFIER_FACE);
102
        if (!is_array($faceList)) {
103
            $faceList = [];
104
        }
105
106
        $profileList = static::getFaceListFromClassifier(self::CLASSIFIER_PROFILE);
107
        if (!is_array($profileList)) {
108
            $profileList = [];
109
        }
110
111
        $faceList = array_merge($faceList, $profileList);
112
113
        return $faceList;
114
    }
115
116
    /**
117
     * getFaceListFromClassifier
118
     *
119
     * @param string $classifier
120
     * @access protected
121
     * @return array
122
     */
123
    protected static function getFaceListFromClassifier($classifier)
124
    {
125
        $file = tmpfile();
126
        static::$originalImage->writeImageFile($file);
0 ignored issues
show
Bug introduced by
The method writeImageFile cannot be called on static::$originalImage (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
127
        $meta_data = stream_get_meta_data($file);
128
        $faceList = face_detect($meta_data['uri'], __DIR__ . $classifier);
129
        fclose($file);
130
        return $faceList;
131
    }
132
133
    /**
134
     * getSafeZoneList
135
     *
136
     * @access private
137
     * @return array
138
     */
139
    protected static function getSafeZoneList()
140
    {
141
        if (!isset(static::$safeZoneList)) {
142
            static::$safeZoneList = array();
143
        }
144
        // the local key is the current image width-height
145
        $key = static::$originalImage->getImageWidth() . '-' . static::$originalImage->getImageHeight();
0 ignored issues
show
Bug introduced by
The method getImageWidth cannot be called on static::$originalImage (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
Bug introduced by
The method getImageHeight cannot be called on static::$originalImage (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
146
147
        if (!isset(static::$safeZoneList[$key])) {
148
            $faceList = static::getFaceList();
149
150
            // getFaceList works on the main image, so we use a ratio between main/current image
151
            $xRatio = static::getBaseDimension('width') / static::$originalImage->getImageWidth();
0 ignored issues
show
Bug introduced by
The method getImageWidth cannot be called on static::$originalImage (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
152
            $yRatio = static::getBaseDimension('height') / static::$originalImage->getImageHeight();
0 ignored issues
show
Bug introduced by
The method getImageHeight cannot be called on static::$originalImage (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
153
154
            $safeZoneList = array();
155
            foreach ($faceList as $face) {
156
                $hw = ceil($face['w'] / 2);
157
                $hh = ceil($face['h'] / 2);
158
                $safeZone = array(
159
                    'left' => $face['x'] - $hw,
160
                    'right' => $face['x'] + $face['w'] + $hw,
161
                    'top' => $face['y'] - $hh,
162
                    'bottom' => $face['y'] + $face['h'] + $hh
163
                );
164
165
                $safeZoneList[] = array(
166
                    'left' => round($safeZone['left'] / $xRatio),
167
                    'right' => round($safeZone['right'] / $xRatio),
168
                    'top' => round($safeZone['top'] / $yRatio),
169
                    'bottom' => round($safeZone['bottom'] / $yRatio),
170
                );
171
            }
172
            static::$safeZoneList[$key] = $safeZoneList;
173
        }
174
175
        return static::$safeZoneList[$key];
176
    }
177
}
178