Completed
Push — master ( ceae2f...40e87c )
by Tim
14:29
created

DimensionService   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 235
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 10
Bugs 1 Features 0
Metric Value
wmc 20
c 10
b 1
f 0
lcom 1
cbo 4
dl 0
loc 235
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getCropMode() 0 10 3
B getFocusWidthAndHeight() 0 24 3
A calculateSourcePosition() 0 19 3
B getShiftedFocusAreaPosition() 0 23 4
B getShiftedFocusPointPosition() 0 33 1
A getRatio() 0 20 4
A mapDatabaseRatio() 0 14 2
1
<?php
2
/**
3
 * Calc dimensions for focus point cropping
4
 *
5
 * @package Focuspoint\Service
6
 * @author  Tim Lochmüller
7
 */
8
9
namespace HDNET\Focuspoint\Service;
10
11
use HDNET\Focuspoint\Utility\GlobalUtility;
12
use TYPO3\CMS\Core\Utility\MathUtility;
13
14
/**
15
 * Calc dimensions for focus point cropping
16
 *
17
 * @author Tim Lochmüller
18
 */
19
class DimensionService extends AbstractService
20
{
21
22
    /**
23
     * Crop mode. Not necessary
24
     */
25
    const CROP_NONE = 0;
26
27
    /**
28
     * Crop in landscape
29
     */
30
    const CROP_LANDSCAPE = 1;
31
32
    /**
33
     * Crop in portrait
34
     */
35
    const CROP_PORTRAIT = 2;
36
37
    /**
38
     * Calc the ratio and check if the crop is landscape or portrait relevant
39
     *
40
     * @param int $width
41
     * @param int $height
42
     * @param string $ratio In format "1:1"
43
     *
44
     * @return int
45
     */
46
    public function getCropMode($width, $height, $ratio)
47
    {
48
        $ratio = $this->getRatio($ratio);
49
        $widthDiff = $width / $ratio[0];
50
        $heightDiff = $height / $ratio[1];
51
        if ($widthDiff == $heightDiff) {
52
            return self::CROP_NONE;
53
        }
54
        return $widthDiff > $heightDiff ? self::CROP_LANDSCAPE : self::CROP_PORTRAIT;
55
    }
56
57
    /**
58
     * Calc the focus width and height by the given ratio
59
     *
60
     * @param int $width
61
     * @param int $height
62
     * @param string $ratio In format "1:1"
63
     *
64
     * @return array
65
     */
66
    public function getFocusWidthAndHeight($width, $height, $ratio)
67
    {
68
        $width = (int)$width;
69
        $height = (int)$height;
70
        $ratio = $this->getRatio($ratio);
71
        $widthDiff = $width / $ratio[0];
72
        $heightDiff = $height / $ratio[1];
73
74
        if ($widthDiff < $heightDiff) {
75
            return [
76
                $width,
77
                (int)ceil($widthDiff / $heightDiff * $height)
78
            ];
79
        } elseif ($widthDiff > $heightDiff) {
80
            return [
81
                (int)ceil($heightDiff / $widthDiff * $width),
82
                $height
83
            ];
84
        }
85
        return [
86
            $width,
87
            $height
88
        ];
89
    }
90
91
    /**
92
     * Calculate the source X and Y position
93
     *
94
     * @param int $cropMode
95
     * @param int $width
96
     * @param int $height
97
     * @param int $focusWidth
98
     * @param int $focusHeight
99
     * @param int $focusPointX
100
     * @param int $focusPointY
101
     *
102
     * @return array
103
     */
104
    public function calculateSourcePosition(
105
        $cropMode,
106
        $width,
107
        $height,
108
        $focusWidth,
109
        $focusHeight,
110
        $focusPointX,
111
        $focusPointY
112
    ) {
113
        if ($cropMode == DimensionService::CROP_PORTRAIT) {
114
            return array_reverse($this->getShiftedFocusAreaPosition($height, $focusHeight, $focusPointY, true));
115
        } elseif ($cropMode == DimensionService::CROP_LANDSCAPE) {
116
            return $this->getShiftedFocusAreaPosition($width, $focusWidth, $focusPointX);
117
        }
118
        return [
119
            0,
120
            0
121
        ];
122
    }
123
124
    /**
125
     * Calc the shifted focus area
126
     *
127
     * @param int $length
128
     * @param int $focusLength
129
     * @param int $focusPosition
130
     * @param bool $invertScala
131
     *
132
     * @return array
133
     */
134
    protected function getShiftedFocusAreaPosition($length, $focusLength, $focusPosition, $invertScala = false)
135
    {
136
        $halfWidth = $length / 2;
137
        $pixelPosition = (int)floor($halfWidth * $focusPosition / 100 + $halfWidth);
138
        if ($invertScala) {
139
            $pixelPosition = $length - $pixelPosition;
140
        }
141
        $crop1 = (int)($pixelPosition - floor($focusLength / 2));
142
        $crop2 = (int)($crop1 + $focusLength);
143
        if ($crop1 < 0) {
144
            $crop1 -= $crop1;
145
        } elseif ($crop2 > $length) {
146
            $diff = $crop2 - $length;
147
            $crop1 -= $diff;
148
        }
149
150
        $sourceX = $crop1;
151
        $sourceY = 0;
152
        return [
153
            $sourceX,
154
            $sourceY
155
        ];
156
    }
157
158
    /**
159
     * get the shifted focus point point position
160
     * for e.g. Frontend handling of the new created image
161
     *
162
     * @param int $imgWidth
163
     * @param int $imgHeight
164
     * @param int $focusX
165
     * @param int $focusY
166
     * @param string $ratio
167
     *
168
     * @return array
169
     */
170
    public function getShiftedFocusPointPosition($imgWidth, $imgHeight, $focusX, $focusY, $ratio)
171
    {
172
        $halfWidth = $imgWidth / 2;
173
        $halfHeight = $imgHeight / 2;
174
175
        $realFocusX = $halfWidth + ($focusX / 100 * $halfWidth);
176
        $realFocusY = $halfHeight - ($focusY / 100 * $halfHeight);
177
178
        list($focusWidth, $focusHeight) = $this->getFocusWidthAndHeight($imgWidth, $imgHeight, $ratio);
179
180
        list($sourceX, $sourceY) = $this->calculateSourcePosition(
181
            $imgWidth,
182
            $imgHeight,
183
            $focusWidth,
184
            $focusHeight,
185
            $focusX,
186
            $focusY,
187
            $ratio
188
        );
189
190
        $newHalfWidth = $focusWidth / 2;
191
        $newHalfHeight = $focusHeight / 2;
192
193
        $newRealFocusX = $realFocusX - $sourceX;
194
        $newRealFocusY = $realFocusY - $sourceY;
195
196
        $newFocusX = ($newRealFocusX - $newHalfWidth) * 100 / ($newHalfWidth);
197
        $newFocusY = ($newHalfHeight - $newRealFocusY) * 100 / ($newHalfHeight);
198
        $newFocusX = (int)round($newFocusX, 0);
199
        $newFocusY = (int)round($newFocusY, 0);
200
201
        return [$newFocusX, $newFocusY];
202
    }
203
204
    /**
205
     * Check the ratio and create an array
206
     *
207
     * @param string $ratio
208
     *
209
     * @return array
210
     * @throws \Exception
211
     */
212
    public function getRatio($ratio)
213
    {
214
        $ratio = $this->mapDatabaseRatio($ratio);
215
        $ratio = explode(':', $ratio);
216
        if (sizeof($ratio) !== 2) {
217
            throw new \Exception('Ratio have to be in the format of e.g. "1:1" or "16:9"', 34627384862);
218
        }
219
        return [
220
            MathUtility::canBeInterpretedAsInteger($ratio[0]) ? (int)$ratio[0] : (float)str_replace(
221
                ',',
222
                '.',
223
                $ratio[0]
224
            ),
225
            MathUtility::canBeInterpretedAsInteger($ratio[1]) ? (int)$ratio[1] : (float)str_replace(
226
                ',',
227
                '.',
228
                $ratio[1]
229
            ),
230
        ];
231
    }
232
233
    /**
234
     * Map the given ratio to the DB table
235
     *
236
     * @param string $ratio
237
     * @return string
238
     */
239
    protected function mapDatabaseRatio($ratio)
240
    {
241
        $databaseConnection = GlobalUtility::getDatabaseConnection();
242
        $table = 'tx_focuspoint_domain_model_dimension';
243
        $row = $databaseConnection->exec_SELECTgetSingleRow(
244
            '*',
245
            $table,
246
            'identifier=' . $databaseConnection->fullQuoteStr($ratio, $table)
247
        );
248
        if (isset($row['dimension'])) {
249
            return $row['dimension'];
250
        }
251
        return $ratio;
252
    }
253
}
254