Completed
Pull Request — master (#16)
by
unknown
15:13
created

getCroppedImageSrcByFileReference()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 10
rs 9.4285
cc 3
eloc 6
nc 4
nop 2
1
<?php
2
/**
3
 * Crop images via focus crop
4
 *
5
 * @package Focuspoint\Service
6
 * @author  Tim Lochmüller
7
 */
8
9
namespace HDNET\Focuspoint\Service;
10
11
use HDNET\Focuspoint\Service\WizardHandler\Group;
12
use HDNET\Focuspoint\Utility\GlobalUtility;
13
use TYPO3\CMS\Core\Imaging\GraphicalFunctions;
14
use TYPO3\CMS\Core\Resource\FileInterface;
15
use TYPO3\CMS\Core\Resource\FileReference as CoreFileReference;
16
use TYPO3\CMS\Core\Resource\ResourceFactory;
17
use TYPO3\CMS\Core\Utility\GeneralUtility;
18
use TYPO3\CMS\Core\Utility\MathUtility;
19
use TYPO3\CMS\Core\Utility\PathUtility;
20
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
21
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
22
use TYPO3\CMS\Frontend\Imaging\GifBuilder;
23
24
/**
25
 * Crop images via focus crop
26
 *
27
 * @author Tim Lochmüller
28
 */
29
class FocusCropService extends AbstractService
30
{
31
32
    const SIGNAL_tempImageCropped = 'tempImageCropped';
33
34
    /**
35
     * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
36
     */
37
    protected $signalSlotDispatcher;
38
39
    /**
40
     * get the image
41
     *
42
     * @param $src
43
     * @param $image
44
     * @param $treatIdAsReference
45
     *
46
     * @return \TYPO3\CMS\Core\Resource\File|FileInterface|CoreFileReference|\TYPO3\CMS\Core\Resource\Folder
47
     * @throws \TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException
48
     * @throws \TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException
49
     */
50
    public function getViewHelperImage($src, $image, $treatIdAsReference)
51
    {
52
        $resourceFactory = ResourceFactory::getInstance();
53
        if ($image instanceof FileReference) {
54
            $image = $image->getOriginalResource();
55
        }
56
        if ($image instanceof CoreFileReference) {
57
            return $image->getOriginalFile();
58
        }
59
        if (!MathUtility::canBeInterpretedAsInteger($src)) {
60
            return $resourceFactory->retrieveFileOrFolderObject($src);
61
        }
62
        if (!$treatIdAsReference) {
63
            return $resourceFactory->getFileObject($src);
64
        }
65
        $image = $resourceFactory->getFileReferenceObject($src);
66
        return $image->getOriginalFile();
67
    }
68
69
    /**
70
     * Helper function for view helpers
71
     *
72
     * @param $src
73
     * @param $image
74
     * @param $treatIdAsReference
75
     * @param $ratio
76
     *
77
     * @throws \TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException
78
     * @throws \TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException
79
     *
80
     * @return string
81
     */
82
    public function getCroppedImageSrcForViewHelper($src, $image, $treatIdAsReference, $ratio)
83
    {
84
        $file = $this->getViewHelperImage($src, $image, $treatIdAsReference);
85
        return $this->getCroppedImageSrcByFile($file, $ratio);
0 ignored issues
show
Bug introduced by
It seems like $file defined by $this->getViewHelperImag...e, $treatIdAsReference) on line 84 can also be of type object<TYPO3\CMS\Core\Resource\Folder>; however, HDNET\Focuspoint\Service...CroppedImageSrcByFile() does only seem to accept object<TYPO3\CMS\Core\Resource\FileInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
86
    }
87
88
    /**
89
     * Get the cropped image
90
     *
91
     * @param string $fileReference
92
     * @param string $ratio
93
     *
94
     * @return string The new filename
95
     */
96
    public function getCroppedImageSrcByFileReference($fileReference, $ratio)
97
    {
98
        if ($fileReference instanceof FileReference) {
99
            $fileReference = $fileReference->getOriginalResource();
100
        }
101
        if ($fileReference instanceof CoreFileReference) {
102
            return $this->getCroppedImageSrcByFile($fileReference->getOriginalFile(), $ratio);
103
        }
104
        throw new \InvalidArgumentException('The given argument is not a valid file reference', 123671283);
105
    }
106
107
    /**
108
     * Get the cropped image by File Object
109
     *
110
     * @param FileInterface $file
111
     * @param string $ratio
112
     *
113
     * @return string The new filename
114
     */
115
    public function getCroppedImageSrcByFile(FileInterface $file, $ratio)
116
    {
117
        return $this->getCroppedImageSrcBySrc(
118
            $file->getPublicUrl(),
119
            $ratio,
120
            $file->getProperty('focus_point_x'),
121
            $file->getProperty('focus_point_y')
122
        );
123
    }
124
125
126
    /**
127
     * Get the cropped image by src
128
     *
129
     * @param string $src Relative file name
130
     * @param string $ratio
131
     * @param int $x
132
     * @param int $y
133
     *
134
     * @return string The new filename
135
     */
136
    public function getCroppedImageSrcBySrc($src, $ratio, $x, $y)
137
    {
138
        $absoluteImageName = GeneralUtility::getFileAbsFileName($src);
139
        if (!is_file($absoluteImageName)) {
140
            return null;
141
        }
142
        $focusPointX = MathUtility::forceIntegerInRange((int)$x, -100, 100, 0);
143
        $focusPointY = MathUtility::forceIntegerInRange((int)$y, -100, 100, 0);
144
145
        if ($focusPointX === 0 && $focusPointY === 0) {
146
            $connection = GlobalUtility::getDatabaseConnection();
147
            $row = $connection->exec_SELECTgetSingleRow(
148
                'uid,focus_point_x,focus_point_y',
149
                Group::TABLE,
150
                'relative_file_path = ' . $connection->fullQuoteStr($src, Group::TABLE)
151
            );
152
            if ($row) {
153
                $focusPointX = MathUtility::forceIntegerInRange((int)$row['focus_point_x'], -100, 100, 0);
154
                $focusPointY = MathUtility::forceIntegerInRange((int)$row['focus_point_y'], -100, 100, 0);
155
            }
156
        }
157
158
        $hash = function_exists('sha1_file') ? sha1_file($absoluteImageName) : md5_file($absoluteImageName);
159
        $tempImageFolder = 'typo3temp/focuscrop/';
160
        $tempImageName = $tempImageFolder . $hash . '-fp-' . preg_replace(
161
            '/[^0-9]/',
162
            '-',
163
            $ratio
164
        ) . '-' . $focusPointX . '-' . $focusPointY . '.' . PathUtility::pathinfo(
165
            $absoluteImageName,
166
            PATHINFO_EXTENSION
167
        );
168
        $tempImageName = preg_replace('/--+/', '-', $tempImageName);
169
        $absoluteTempImageName = GeneralUtility::getFileAbsFileName($tempImageName);
170
171
        if (is_file($absoluteTempImageName)) {
172
            return $tempImageName;
173
        }
174
175
        $absoluteTempImageFolder = GeneralUtility::getFileAbsFileName($tempImageFolder);
176
        if (!is_dir($absoluteTempImageFolder)) {
177
            GeneralUtility::mkdir_deep($absoluteTempImageFolder);
178
        }
179
180
        $imageSizeInformation = getimagesize($absoluteImageName);
181
        $width = $imageSizeInformation[0];
182
        $height = $imageSizeInformation[1];
183
184
        // dimensions
185
        /** @var DimensionService $dimensionService */
186
        $dimensionService = GeneralUtility::makeInstance(DimensionService::class);
187
        list($focusWidth, $focusHeight) = $dimensionService->getFocusWidthAndHeight($width, $height, $ratio);
188
        $cropMode = $dimensionService->getCropMode($width, $height, $ratio);
189
        list($sourceX, $sourceY) = $dimensionService->calculateSourcePosition(
190
            $cropMode,
191
            $width,
192
            $height,
193
            $focusWidth,
194
            $focusHeight,
195
            $focusPointX,
196
            $focusPointY
197
        );
198
199
        // generate image
200
        if (strtolower(PathUtility::pathinfo($absoluteImageName, PATHINFO_EXTENSION)) == 'png') {
201
            $this->createCropImageGifBuilder(
202
                $absoluteImageName,
203
                $focusWidth,
204
                $focusHeight,
205
                $sourceX,
206
                $sourceY,
207
                $absoluteTempImageName
208
            );
209
        } else {
210
            $this->createCropImageGraphicalFunctions(
211
                $absoluteImageName,
212
                $focusWidth,
213
                $focusHeight,
214
                $sourceX,
215
                $sourceY,
216
                $absoluteTempImageName
217
            );
218
        }
219
220
        $this->emitTempImageCropped($tempImageName);
221
222
        return $tempImageName;
223
    }
224
225
    /**
226
     * Create the crop image (GifBuilder)
227
     *
228
     * @param $absoluteImageName
229
     * @param $focusWidth
230
     * @param $focusHeight
231
     * @param $sourceX
232
     * @param $sourceY
233
     * @param $absoluteTempImageName
234
     */
235
    protected function createCropImageGifBuilder(
236
        $absoluteImageName,
237
        $focusWidth,
238
        $focusHeight,
239
        $sourceX,
240
        $sourceY,
241
        $absoluteTempImageName
242
    ) {
243
        $size = getimagesize($absoluteImageName);
244
        $relativeImagePath = rtrim(PathUtility::getRelativePath(
245
            GeneralUtility::getIndpEnv('TYPO3_DOCUMENT_ROOT'),
246
            $absoluteImageName
247
        ), '/');
248
        $configuration = [
249
            'format' => strtolower(PathUtility::pathinfo($absoluteImageName, PATHINFO_EXTENSION)),
250
            'XY' => $size[0] . ',' . $size[1],
251
            'transparentBackground' => '1',
252
            '10' => 'IMAGE',
253
            '10.' => [
254
                'file' => $relativeImagePath,
255
                'file.' => [
256
                    'quality' => $GLOBALS['TYPO3_CONF_VARS']['GFX']['jpg_quality'],
257
                    'width' => $size[0],
258
                    'height' => $size[1],
259
                ],
260
            ],
261
            '20' => 'CROP',
262
            '20.' => [
263
                'crop' => $sourceX . ',' . $sourceY . ',' . $focusWidth . ',' . $focusHeight,
264
            ],
265
        ];
266
267
        /** @var GifBuilder $gifBuilder */
268
        $gifBuilder = GeneralUtility::makeInstance(GifBuilder::class);
269
        $gifBuilder->init();
270
        $gifBuilder->start($configuration, []);
271
        $gifBuilder->createTempSubDir('focuscrop/');
272
        $gifBuilder->make();
273
        $gifBuilder->output($absoluteTempImageName);
274
        $gifBuilder->destroy();
275
    }
276
277
    /**
278
     * Create the crop image (GraphicalFunctions)
279
     *
280
     * @param $absoluteImageName
281
     * @param $focusWidth
282
     * @param $focusHeight
283
     * @param $sourceX
284
     * @param $sourceY
285
     * @param $absoluteTempImageName
286
     */
287
    protected function createCropImageGraphicalFunctions(
288
        $absoluteImageName,
289
        $focusWidth,
290
        $focusHeight,
291
        $sourceX,
292
        $sourceY,
293
        $absoluteTempImageName
294
    ) {
295
        /** @var GraphicalFunctions $graphicalFunctions */
296
        $graphicalFunctions = GeneralUtility::makeInstance(GraphicalFunctions::class);
297
        $sourceImage = $graphicalFunctions->imageCreateFromFile($absoluteImageName);
298
        $destinationImage = imagecreatetruecolor($focusWidth, $focusHeight);
299
300
        // prevent the problem of large images result in a "Allowed memory size" error
301
        // we do not need the alpha layer at all, because the PNG rendered with createCropImageGifBuilder
302
        ObjectAccess::setProperty($graphicalFunctions, 'saveAlphaLayer', true, true);
303
304
        $graphicalFunctions->imagecopyresized(
305
            $destinationImage,
306
            $sourceImage,
307
            0,
308
            0,
309
            $sourceX,
310
            $sourceY,
311
            $focusWidth,
312
            $focusHeight,
313
            $focusWidth,
314
            $focusHeight
315
        );
316
317
        $graphicalFunctions->ImageWrite(
318
            $destinationImage,
319
            $absoluteTempImageName,
320
            $GLOBALS['TYPO3_CONF_VARS']['GFX']['jpg_quality']
321
        );
322
    }
323
324
    /**
325
     * Emit tempImageCropped signal
326
     *
327
     * @param string $tempImageName
328
     * @return string
329
     */
330
    protected function emitTempImageCropped($tempImageName)
331
    {
332
        $this->getSignalSlotDispatcher()->dispatch(__CLASS__, self::SIGNAL_tempImageCropped, array($tempImageName));
333
    }
334
335
    /**
336
     * Get the SignalSlot dispatcher.
337
     *
338
     * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
339
     */
340
    protected function getSignalSlotDispatcher()
341
    {
342
        if (!isset($this->signalSlotDispatcher)) {
343
            $this->signalSlotDispatcher = $this->getObjectManager()->get(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
344
        }
345
        return $this->signalSlotDispatcher;
346
    }
347
348
    /**
349
     * Gets the ObjectManager.
350
     *
351
     * @return \TYPO3\CMS\Extbase\Object\ObjectManager
352
     */
353
    protected function getObjectManager()
354
    {
355
        return GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
356
    }
357
}
358