YeelightImageService::saveImageInfo()   B
last analyzed

Complexity

Conditions 7
Paths 18

Size

Total Lines 37
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 21
nc 18
nop 9
dl 0
loc 37
rs 8.6506
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace Yeelight\Services\Image;
4
5
use Carbon\Carbon;
6
use File;
7
use Image;
8
use Intervention\Image\ImageManager;
9
use Symfony\Component\HttpFoundation\File\UploadedFile;
10
use Validator;
11
use Yeelight\Models\Image\YeelightImage;
12
use Yeelight\Services\Image\Exception\StoreImageException;
13
use Yeelight\Services\Image\Exception\YeelightImageException;
14
use Yeelight\Services\Image\Models\YeelightImageHash;
15
16
/**
17
 * Class YeelightImageService
18
 *
19
 * @category Yeelight
20
 *
21
 * @package Yeelight\Services\Image
22
 *
23
 * @author Sheldon Lee <[email protected]>
24
 *
25
 * @license https://opensource.org/licenses/MIT MIT
26
 *
27
 * @link https://www.yeelight.com
28
 */
29
class YeelightImageService
30
{
31
    /**
32
     * @param $key
33
     * @param null $default
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $default is correct as it would always require null to be passed?
Loading history...
34
     *
35
     * @return mixed
36
     */
37
    public function getConfig($key, $default = null)
38
    {
39
        return config("yeelight-image.$key", $default);
40
    }
41
42
    /**
43
     * @return string
44
     */
45
    private function storagePath()
46
    {
47
        return $this->getConfig('storage_path');
48
    }
49
50
    /**
51
     * @return int
52
     */
53
    private function defaultQuality()
54
    {
55
        return (int) $this->getConfig('default_quality', 75);
56
    }
57
58
    /**
59
     * @return int
60
     */
61
    private function largeImageQuality()
62
    {
63
        return (int) $this->getConfig('large_image_quality', 65);
64
    }
65
66
    /**
67
     * @param UploadedFile $file
68
     * @param string       $additionValidatorRule
69
     * @param bool         $isAllowGIF
70
     * @param int          $maxSizeAllowed
71
     * @param bool         $isStorePNG
72
     *
73
     * @return YeelightImage
74
     */
75
    public function handleUploadedFile(UploadedFile $file, $additionValidatorRule = '', $isAllowGIF = false, $maxSizeAllowed = 12829, $isStorePNG = false)
76
    {
77
        // check valid
78
        if (!$file->isValid()) {
79
            throw new StoreImageException($file->getErrorMessage());
80
        }
81
82
        // validate image
83
        $additionValidatorRule = !empty($additionValidatorRule) ? '|'.$additionValidatorRule : '';
84
        $mimes = $isAllowGIF ? ',gif' : '';
85
        /** @var Validator $validator */
86
        $validator = Validator::make(['image' => $file], [
87
            'image' => 'required|mimes:jpg,jpeg,bmp,png'.$mimes.'|max:'.$maxSizeAllowed.$additionValidatorRule,
88
        ]);
89
        if ($validator->fails()) {
0 ignored issues
show
Bug introduced by
The method fails() does not exist on Illuminate\Support\Facades\Validator. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

89
        if ($validator->/** @scrutinizer ignore-call */ fails()) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
90
            throw new StoreImageException($validator->errors()->first());
0 ignored issues
show
Bug introduced by
The method errors() does not exist on Illuminate\Support\Facades\Validator. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

90
            throw new StoreImageException($validator->/** @scrutinizer ignore-call */ errors()->first());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
91
        }
92
93
        // file info
94
        $path_with_name = $file->getPathname();
95
        $file_extension = $file->getClientOriginalExtension();
96
97
        return $this->storeImageFromPath($path_with_name, $file_extension, $isAllowGIF, $isStorePNG);
98
    }
99
100
    /**
101
     * @param $path_with_name
102
     * @param null $file_extension
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $file_extension is correct as it would always require null to be passed?
Loading history...
103
     * @param bool $isAllowGIF
104
     * @param bool $isStorePNG
105
     *
106
     * @return null|YeelightImage
107
     */
108
    public function storeImageFromPath($path_with_name, $file_extension = null, $isAllowGIF = false, $isStorePNG = false)
109
    {
110
        $file_extension = $file_extension ?: pathinfo($path_with_name, PATHINFO_EXTENSION);
111
        $is_file_gif = $file_extension == 'gif';
112
        $is_file_png = $file_extension == 'png';
113
        $file_origin_size = filesize($path_with_name);
114
        $is_animated_gif = $is_file_gif && $this->isAnimatedGif($path_with_name);
115
116
        if (!File::exists($path_with_name)) {
117
            throw new StoreImageException('File not found: '.$path_with_name);
118
        }
119
120
        // read exif info
121
        $exif = read_exif_data_safe($path_with_name);
122
123
        // passed validation and make image
124
        $image = Image::make($path_with_name);
125
        $originWidth = $image->getWidth();
0 ignored issues
show
Unused Code introduced by
The assignment to $originWidth is dead and can be removed.
Loading history...
126
        $originHeight = $image->getHeight();
0 ignored issues
show
Unused Code introduced by
The assignment to $originHeight is dead and can be removed.
Loading history...
127
        $image_file_size_kb = $file_origin_size / 1024;
0 ignored issues
show
Unused Code introduced by
The assignment to $image_file_size_kb is dead and can be removed.
Loading history...
128
        $is_allowed_animated_gif = $is_animated_gif;
129
130
        // save as jpg
131
        $default_file_extension = 'jpg';
132
        // save as gif if is allowed
133
        if ($isAllowGIF && $is_allowed_animated_gif) {
134
            $default_file_extension = 'gif';
135
        }
136
        if ($isStorePNG && $is_file_png) {
137
            $default_file_extension = 'png';
138
        }
139
        $storage_path = $this->storagePath();
140
        $file_sha1 = sha1_file($path_with_name);
141
        $final_file_sha1 = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $final_file_sha1 is dead and can be removed.
Loading history...
142
        if ($file_sha1 === false) {
143
            throw new StoreImageException('Failed to create SHA1 for file: '.$path_with_name);
144
        }
145
146
        // final
147
        $final_file_name = strtolower($file_sha1.'.'.$default_file_extension);
148
        $final_path_with_name = $storage_path.$final_file_name;
149
150
        // check directory
151
        if (!self::autoCreateDirectory($final_path_with_name)) {
152
            throw new StoreImageException('Failed to make dir: '.dirname($final_path_with_name));
153
        }
154
155
        // save
156
        $isExists = File::exists($final_path_with_name);
157
        $isSimilarExists = false;
158
        $yeelight_image_hash = null;
159
        $final_file_sha1 = null;
160
        $final_file_size = null;
161
        if ($isExists) {
162
            $final_file_sha1 = $file_sha1;
163
            $final_file_size = filesize($final_path_with_name);
164
        } else {
165
            $yeelight_image_hash = YeelightImageHash::where(['file_sha1' => $file_sha1])->first();
166
            $isExists = $isSimilarExists = $yeelight_image_hash ? true : false;
167
        }
168
169
        if (!$isExists) {
170
            if (($isAllowGIF && $is_allowed_animated_gif) || ($isStorePNG && $is_file_png)) {
171
                if (File::copy($path_with_name, $final_path_with_name)) {
172
                    @chmod($final_path_with_name, 0666 & ~umask());
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

172
                    /** @scrutinizer ignore-unhandled */ @chmod($final_path_with_name, 0666 & ~umask());

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
173
                } else {
174
                    throw new StoreImageException('Failed to move file to path: '.$final_path_with_name);
175
                }
176
                $final_file_sha1 = sha1_file($final_path_with_name);
177
                $final_file_size = filesize($final_path_with_name);
178
                $isExists = File::exists($final_path_with_name);
179
            } else {
180
                $isExists = $this->saveImage($image, $exif,
181
                    $final_path_with_name, $final_file_sha1, $final_file_size);
0 ignored issues
show
Bug introduced by
It seems like $final_file_size can also be of type integer; however, parameter $final_file_size of Yeelight\Services\Image\...ageService::saveImage() does only seem to accept null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

181
                    $final_path_with_name, $final_file_sha1, /** @scrutinizer ignore-type */ $final_file_size);
Loading history...
Bug introduced by
It seems like $final_file_sha1 can also be of type string; however, parameter $final_file_sha1 of Yeelight\Services\Image\...ageService::saveImage() does only seem to accept null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

181
                    $final_path_with_name, /** @scrutinizer ignore-type */ $final_file_sha1, $final_file_size);
Loading history...
182
            }
183
        }
184
185
        // stored and save to database
186
        $yeelight_image = null;
187
        if ($isExists) {
188
            $yeelight_image = $this->saveImageInfo($isSimilarExists, $yeelight_image_hash,
189
                $final_file_name, $is_allowed_animated_gif, $final_file_size, $image, $exif,
190
                $file_sha1, $final_file_sha1);
191
        }
192
193
        if (!$yeelight_image) {
194
            throw new StoreImageException('Failed to store image.');
195
        }
196
197
        return $yeelight_image;
198
    }
199
200
    /**
201
     * @param $originImageEncodedData
202
     * @param bool $isAllowGIF
203
     *
204
     * @return null|YeelightImage
205
     */
206
    public function storeImageFromURLEncodedImageData($originImageEncodedData, $isAllowGIF = false)
207
    {
208
        $exif = read_exif_data_safe($originImageEncodedData);
209
        $is_gif = self::isDataURLEncodedImageGif($originImageEncodedData);
210
        $origin_image_data = self::convertDataURLEncodedToImageData($originImageEncodedData);
211
        $origin_image_sha1 = sha1($origin_image_data);
212
213
        return $this->storeImageFromMake($origin_image_data, $origin_image_sha1, $exif, $isAllowGIF, $is_gif);
214
    }
215
216
    /**
217
     * @param $source
218
     * @param $file_sha1
219
     * @param $exif
220
     * @param bool $isAllowGIF
221
     * @param bool $isGIF
222
     *
223
     * @return YeelightImage
224
     */
225
    public function storeImageFromMake($source, $file_sha1, $exif, $isAllowGIF = false, $isGIF = false)
226
    {
227
        try {
228
            $image = Image::make($source);
229
        } catch (StoreImageException $e) {
230
            throw new StoreImageException('YeelightImageService: Unable to make image [' + (string) $e + ']');
231
        }
232
233
        $is_allowed_animated_gif = $isAllowGIF && $isGIF;
234
235
        // save as jpg
236
        $default_file_extension = 'jpg';
237
        // save as gif if is allowed
238
        if ($isAllowGIF && $is_allowed_animated_gif) {
239
            $default_file_extension = 'gif';
240
        }
241
        $storage_path = $this->storagePath();
242
        $final_file_sha1 = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $final_file_sha1 is dead and can be removed.
Loading history...
243
        if ($file_sha1 === false || strlen($file_sha1) != 40) {
244
            throw new StoreImageException('Invalid SHA1 for file.');
245
        }
246
247
        // final
248
        $final_file_name = strtolower($file_sha1.'.'.$default_file_extension);
249
        $final_path_with_name = $storage_path.$final_file_name;
250
251
        // check directory
252
        if (!self::autoCreateDirectory($final_path_with_name)) {
253
            throw new StoreImageException('Failed to make dir: '.dirname($final_path_with_name));
254
        }
255
256
        // save
257
        $isExists = File::exists($final_path_with_name);
258
        $isSimilarExists = false;
259
        $yeelight_image_hash = null;
260
        $final_file_sha1 = null;
261
        $final_file_size = null;
262
        if ($isExists) {
263
            $final_file_sha1 = $file_sha1;
264
            $final_file_size = filesize($final_path_with_name);
265
        } else {
266
            $yeelight_image_hash = YeelightImageHash::where(['file_sha1' => $file_sha1])->first();
267
            $isExists = $isSimilarExists = $yeelight_image_hash ? true : false;
268
        }
269
270
        if (!$isExists) {
271
            if ($isAllowGIF && $is_allowed_animated_gif) {
272
                if (file_put_contents($final_path_with_name, $source)) {
273
                    @chmod($final_path_with_name, 0666 & ~umask());
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

273
                    /** @scrutinizer ignore-unhandled */ @chmod($final_path_with_name, 0666 & ~umask());

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
274
                } else {
275
                    throw new StoreImageException('Failed to move file to path: '.$final_path_with_name);
276
                }
277
                $final_file_sha1 = sha1_file($final_path_with_name);
278
                $final_file_size = filesize($final_path_with_name);
279
                $isExists = File::exists($final_path_with_name);
280
            } else {
281
                $isExists = $this->saveImage($image, $exif,
282
                    $final_path_with_name, $final_file_sha1, $final_file_size);
0 ignored issues
show
Bug introduced by
It seems like $final_file_size can also be of type integer; however, parameter $final_file_size of Yeelight\Services\Image\...ageService::saveImage() does only seem to accept null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

282
                    $final_path_with_name, $final_file_sha1, /** @scrutinizer ignore-type */ $final_file_size);
Loading history...
283
            }
284
        }
285
286
        // stored and save to database
287
        $yeelight_image = null;
288
        if ($isExists) {
289
            $yeelight_image = $this->saveImageInfo($isSimilarExists, $yeelight_image_hash,
290
                $final_file_name, $is_allowed_animated_gif, $final_file_size, $image, $exif,
291
                $file_sha1, $final_file_sha1);
292
        }
293
294
        if (!$yeelight_image) {
295
            throw new StoreImageException('Failed to store image.');
296
        }
297
298
        return $yeelight_image;
299
    }
300
301
    /**
302
     * @param $filename
303
     *
304
     * @return bool
305
     */
306
    public function isAnimatedGif($filename)
307
    {
308
        $file_contents = file_get_contents($filename);
309
310
        $str_loc = 0;
311
        $count = 0;
312
313
        // There is no point in continuing after we find a 2nd frame
314
        while ($count < 2) {
315
            $where1 = strpos($file_contents, "\x00\x21\xF9\x04", $str_loc);
316
            if ($where1 === false) {
317
                break;
318
            }
319
320
            $str_loc = $where1 + 1;
321
            $where2 = strpos($file_contents, "\x00\x2C", $str_loc);
322
            if ($where2 === false) {
323
                break;
324
            } else {
325
                if ($where1 + 8 == $where2) {
326
                    $count++;
327
                }
328
                $str_loc = $where2 + 1;
329
            }
330
        }
331
332
        // gif is animated when it has two or more frames
333
        return $count >= 2;
334
    }
335
336
    /**
337
     * @param $image_name
338
     *
339
     * @return mixed
340
     */
341
    public function getImageOrFail($image_name)
342
    {
343
        return YeelightImage::where('image_name', $image_name)->firstOrFail();
344
    }
345
346
    /**
347
     * @param $template_name The template to be used for showing
348
     * @param $image_name The image name for showing
0 ignored issues
show
Bug introduced by
The type Yeelight\Services\Image\The was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
349
     * @param $image_templates array Additional image templates, if same template exists, will be replaced
350
     * @param null $storage_path
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $storage_path is correct as it would always require null to be passed?
Loading history...
351
     *
352
     * @return mixed|\Symfony\Component\HttpFoundation\BinaryFileResponse
353
     */
354
    public function showImage($template_name, $image_name, array $image_templates = [], $storage_path = null)
355
    {
356
        $cache_minutes = 60 * 24 * 15; // 15 days
357
        $storage_path = $storage_path ?: $this->storagePath();
358
        $image_templates = array_merge($this->getConfig('image_templates', []), $image_templates);
359
        $file_path = $storage_path.$image_name;
360
361
        // check exists
362
        $isExists = File::exists($file_path);
363
        if (!$isExists) {
364
            abort(404);
365
        }
366
367
        // if is invalid type
368
        if (!isset($image_templates[$template_name])) {
369
            throw new YeelightImageException('Invalid template name supplied.');
370
        }
371
372
        /** @var ImageTemplate $imageTemplate */
373
        $imageTemplate = $image_templates[$template_name];
374
375
        // if download
376
        if ($imageTemplate->isDownload()) {
377
            return response()->download($file_path);
0 ignored issues
show
Bug introduced by
The method download() does not exist on Symfony\Component\HttpFoundation\Response. It seems like you code against a sub-type of Symfony\Component\HttpFoundation\Response such as Illuminate\Http\Response or Illuminate\Http\JsonResponse or Illuminate\Http\RedirectResponse. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

377
            return response()->/** @scrutinizer ignore-call */ download($file_path);
Loading history...
378
        }
379
380
        // if gif
381
        if (str_contains($image_name, 'gif')) {
382
            return response(file_get_contents($file_path), 200)
383
                ->header('Content-Type', 'image/gif')
0 ignored issues
show
Bug introduced by
The method header() does not exist on Symfony\Component\HttpFoundation\Response. It seems like you code against a sub-type of Symfony\Component\HttpFoundation\Response such as Illuminate\Http\Response or Illuminate\Http\JsonResponse or Illuminate\Http\RedirectResponse. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

383
                ->/** @scrutinizer ignore-call */ header('Content-Type', 'image/gif')
Loading history...
384
                ->setPublic()
385
                ->setMaxAge(604800)
386
                ->setExpires(Carbon::now()->addDay(7));
387
        }
388
389
        // convert to image
390
        $img = Image::cache(function ($image) use ($file_path, $imageTemplate) {
391
            /* @var \Intervention\Image\Image $image */
392
            $image->make($file_path);
393
394
            // resize
395
            if (!$imageTemplate->isOriginal()) {
396
                if ($imageTemplate->isHeighten()) {
397
                    $image->heighten($imageTemplate->getHeight(), function ($constraint) use ($imageTemplate) {
398
                        if ($imageTemplate->isRatio()) {
399
                            $constraint->aspectRatio();
400
                        }
401
                        $constraint->upsize();
402
                    });
403
                } elseif ($imageTemplate->isWiden()) {
404
                    $image->widen($imageTemplate->getWidth(), function ($constraint) use ($imageTemplate) {
405
                        if ($imageTemplate->isRatio()) {
406
                            $constraint->aspectRatio();
407
                        }
408
                        $constraint->upsize();
409
                    });
410
                } elseif ($imageTemplate->isResize()) {
411
                    // remain aspect ratio and to its largest possible
412
                    if ($imageTemplate->isFit()) {
413
                        $image->fit($imageTemplate->getWidth(), $imageTemplate->getHeight());
414
                    } else {
415
                        $image->resize($imageTemplate->getWidth(), $imageTemplate->getHeight(),
416
                            function ($constraint) use ($imageTemplate) {
417
                                if ($imageTemplate->isRatio()) {
418
                                    $constraint->aspectRatio();
419
                                }
420
                                $constraint->upsize();
421
                            });
422
                    }
423
                }
424
            }
425
426
            // blur
427
            $blur_option = $imageTemplate->getOption('blur');
428
            if (!empty($blur_option)) {
429
                $amount = $blur_option['amount'];
430
                $image->blur($amount);
431
            }
432
        }, $cache_minutes, true);
433
434
        return $img->response()->setPublic()
435
            ->setMaxAge(604800)
436
            ->setExpires(Carbon::now()->addDay(7));
437
    }
438
439
    /**
440
     * @param $image
441
     * @param $exif
442
     * @param $final_path_with_name
443
     * @param null $final_file_sha1
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $final_file_sha1 is correct as it would always require null to be passed?
Loading history...
444
     * @param null $final_file_size
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $final_file_size is correct as it would always require null to be passed?
Loading history...
445
     *
446
     * @return bool
447
     */
448
    public function saveImage($image, $exif, $final_path_with_name,
449
                              &$final_file_sha1 = null, &$final_file_size = null)
450
    {
451
        // set correct orientation
452
        if (!empty($exif) && is_array($exif)) {
453
            if (isset($exif['Orientation']) && $exif['Orientation'] != 1) {
454
                $orientation = $exif['Orientation'];
455
                $deg = 0;
456
                switch ($orientation) {
457
                    case 3:
458
                        $deg = 180;
459
                        break;
460
                    case 6:
461
                        $deg = 270;
462
                        break;
463
                    case 8:
464
                        $deg = 90;
465
                        break;
466
                }
467
                // rotate image
468
                $image->rotate($deg);
469
            }
470
        }
471
472
        // basic info
473
        $originWidth = $image->getWidth();
474
        $originHeight = $image->getHeight();
475
        $file_origin_size = $image->filesize();
476
        $image_file_size_kb = $file_origin_size / 1024;
477
478
        // default quality 75
479
        $image_quality = $this->defaultQuality();
480
481
        // higher quality for small images
482
        if ($image_file_size_kb < 500) {
483
            $image_quality = 100;
484
        }
485
486
        // higher compression for large size images, 2000kb
487
        if ($image_file_size_kb > 2000) {
488
            // quality 65
489
            $image_quality = $this->largeImageQuality();
490
        }
491
492
        // reduce dimension to max 5000px
493
        $maxDimensionAllow = 5000;
494
        if ($originWidth > $maxDimensionAllow || $originHeight > $maxDimensionAllow) {
495
            $newWidth = $newHeight = null;
496
            if ($originWidth >= $originHeight) {
497
                $newWidth = $maxDimensionAllow;
498
            } else {
499
                $newHeight = $maxDimensionAllow;
500
            }
501
502
            // resize
503
            $image->resize($newWidth, $newHeight, function ($constraint) {
504
                $constraint->aspectRatio();
505
                $constraint->upsize();
506
            });
507
        }
508
509
        // save as JPG
510
        $image->save($final_path_with_name, $image_quality);
511
        $final_file_sha1 = sha1_file($final_path_with_name);
512
        $final_file_size = filesize($final_path_with_name);
513
        $isSaved = File::exists($final_path_with_name);
514
515
        return $isSaved;
516
    }
517
518
    /**
519
     * @param $isSimilarExists
520
     * @param $yeelight_image_hash
521
     * @param $final_file_name
522
     * @param $is_allowed_animated_gif
523
     * @param $final_file_size
524
     * @param $image
525
     * @param $exif
526
     * @param $file_sha1
527
     * @param $final_file_sha1
528
     *
529
     * @return YeelightImage
530
     */
531
    private function saveImageInfo($isSimilarExists, $yeelight_image_hash, $final_file_name, $is_allowed_animated_gif, $final_file_size, $image, $exif, $file_sha1, $final_file_sha1)
532
    {
533
        // check has Yeelight image
534
        if ($isSimilarExists) {
535
            $yeelight_image = $yeelight_image_hash->image;
536
        } else {
537
            $yeelight_image = YeelightImage::where('image_name', $final_file_name)->first();
538
        }
539
        // if no record, then save
540
        if (!$yeelight_image) {
541
            // read all existing data into an array
542
            $exif_data = $exif && is_array($exif) ? json_encode_safe($exif) : null;
543
544
            // create
545
            $yeelight_image = YeelightImage::firstOrCreate([
546
                'image_name' => $final_file_name,
547
                'is_gif'     => $is_allowed_animated_gif,
548
                'exif'       => $exif_data,
549
                'file_size'  => $final_file_size,
550
                'width'      => $image->getWidth(),
551
                'height'     => $image->getHeight(),
552
            ]);
553
554
            // add to image hash
555
            YeelightImageHash::firstOrCreate([
556
                'yeelight_image_id' => $yeelight_image->yeelight_image_id,
557
                'file_sha1'         => $file_sha1,
558
            ]);
559
            if (!empty($final_file_sha1) && $final_file_sha1 != $file_sha1) {
560
                YeelightImageHash::firstOrCreate([
561
                    'yeelight_image_id' => $yeelight_image->yeelight_image_id,
562
                    'file_sha1'         => $final_file_sha1,
563
                ]);
564
            }
565
        }
566
567
        return $yeelight_image;
568
    }
569
570
    public static function convertDataURLEncodedToImageData($encodedData)
571
    {
572
        try {
573
            $filteredData = substr($encodedData, strpos($encodedData, ',') + 1);
574
            $image_data = base64_decode($filteredData);
575
576
            return $image_data;
577
        } catch (StoreImageException $e) {
578
            \Log::error('YeelightImageService: Unable to convert to image [' + (string) $e + ']');
579
580
            return;
581
        }
582
    }
583
584
    public static function isDataURLEncodedImageGif($encodedData)
585
    {
586
        try {
587
            $image_type = substr($encodedData, 0, strpos($encodedData, ','));
588
            $is_gif = str_contains($image_type, 'gif');
589
590
            return $is_gif;
591
        } catch (StoreImageException $e) {
592
            \Log::error('YeelightImageService: Unable to convert to image [' + (string) $e + ']');
593
594
            return false;
595
        }
596
    }
597
598
    /**
599
     * auto create directory if not exists.
600
     *
601
     * @param $path_name
602
     *
603
     * @return bool
604
     */
605
    public static function autoCreateDirectory($path_name)
606
    {
607
        // check directory
608
        if (!File::exists(dirname($path_name))) {
609
            $isMadeDir = mkdir(dirname($path_name), 0777, true);
610
            if (!$isMadeDir) {
611
                return false;
612
            }
613
        }
614
615
        return true;
616
    }
617
618
    /**
619
     * @param int $yeelight_image_id
620
     *
621
     * @return \Intervention\Image\Image
622
     */
623
    public static function getImageFromYeelightImageId($yeelight_image_id)
624
    {
625
        $yeelight_image = YeelightImage::find($yeelight_image_id);
626
        if (is_null($yeelight_image)) {
627
            throw new YeelightImageException('Yeelight image record not found!');
628
        }
629
        $imageManager = new ImageManager(config('image'));
630
        $background_image = $imageManager->make($yeelight_image->getImagePath());
631
632
        return $background_image;
633
    }
634
}
635