GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Manipulation::displayImage()   A
last analyzed

Complexity

Conditions 5
Paths 12

Size

Total Lines 29
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 18
nc 12
nop 2
dl 0
loc 29
rs 9.3554
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of the O2System Framework package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @author         Steeve Andrian Salim
9
 * @copyright      Copyright (c) Steeve Andrian Salim
10
 */
11
12
// ------------------------------------------------------------------------
13
14
namespace O2System\Image;
15
16
// ------------------------------------------------------------------------
17
18
use O2System\Image\Abstracts\AbstractDriver;
19
use O2System\Image\Abstracts\AbstractWatermark;
20
use O2System\Image\DataStructures\Config;
21
use O2System\Image\Optimizers\Imageoptim;
22
use O2System\Spl\Exceptions\Runtime\FileNotFoundException;
23
24
/**
25
 * Class Manipulation
26
 *
27
 * @package O2System\Image
28
 */
29
class Manipulation
30
{
31
    /**
32
     * Manipulation::ROTATE_CW
33
     *
34
     * Clock wise image rotation degrees.
35
     *
36
     * @var int
37
     */
38
    const ROTATE_CW = 90;
39
40
    /**
41
     * Manipulation::ROTATE_CCW
42
     *
43
     * Counter clock wise image rotation degrees.
44
     *
45
     * @var int
46
     */
47
    const ROTATE_CCW = -90;
48
49
    /**
50
     * Manipulation::FLIP_HORIZONTAL
51
     *
52
     * Flip image with horizontal axis.
53
     *
54
     * @var int
55
     */
56
    const FLIP_HORIZONTAL = 1;
57
58
    /**
59
     * Manipulation::FLIP_VERTICAL
60
     *
61
     * Flip image with vertical axis.
62
     *
63
     * @var int
64
     */
65
    const FLIP_VERTICAL = 2;
66
67
    /**
68
     * Manipulation::FLIP_BOTH
69
     *
70
     * Flip image with horizontal and vertical axis.
71
     *
72
     * @var int
73
     */
74
    const FLIP_BOTH = 3;
75
76
    /**
77
     * Manipulation::ORIENTATION_AUTO
78
     *
79
     * Auto image orientation.
80
     *
81
     * @var string
82
     */
83
    const ORIENTATION_AUTO = 'AUTO';
84
85
    /**
86
     * Manipulation::ORIENTATION_LANDSCAPE
87
     *
88
     * Landscape image orientation.
89
     *
90
     * @var string
91
     */
92
    const ORIENTATION_LANDSCAPE = 'LANDSCAPE';
93
94
    /**
95
     * Manipulation::DIRECTIVE_UP
96
     *
97
     * If the target image size is larger than the size of the source image then the image source size
98
     * will be resized according to the target image size. But if the target image size is smaller than
99
     * the size of the source image then the resulting image size will match the size of the image source.
100
     * In other words the target image size should not be smaller than the size of the source image.
101
     *
102
     * @var string
103
     */
104
    const DIRECTIVE_UP = 'UP';
105
106
    /**
107
     * Manipulation::DIRECTIVE_DOWN
108
     *
109
     * If the target image size is smaller than the size of the source image then the image source size
110
     * will be resized according to the target image size. But if the target image size is larger than
111
     * the size of the source image then the resulting image size will match the size of the image source.
112
     * In other words the target image size can not be larger than the size of the image source.
113
     */
114
    const DIRECTIVE_DOWN = 'DOWN';
115
116
    /**
117
     * Manipulation::DIRECTIVE_RATIO
118
     *
119
     * The source image size will always resized according to the target image size and according to aspect ratio.
120
     *
121
     * @var string
122
     */
123
    const DIRECTIVE_RATIO = 'RATIO';
124
125
    /**
126
     * Manipulation::ORIENTATION_PORTRAIT
127
     *
128
     * Landscape image orientation.
129
     *
130
     * @var string
131
     */
132
    const ORIENTATION_PORTRAIT = 'PORTRAIT';
133
134
    /**
135
     * Manipulation::ORIENTATION_SQUARE
136
     *
137
     * Landscape image orientation.
138
     *
139
     * @var string
140
     */
141
    const ORIENTATION_SQUARE = 'SQUARE';
142
143
    /**
144
     * Manipulation::WATERMARK_CENTER
145
     *
146
     * Watermark center position.
147
     *
148
     * @var string
149
     */
150
    const WATERMARK_CENTER = 'CENTER';
151
152
    /**
153
     * Manipulation::WATERMARK_MIDDLE_LEFT
154
     *
155
     * Watermark middle left position.
156
     *
157
     * @var string
158
     */
159
    const WATERMARK_MIDDLE_LEFT = 'MIDDLE_LEFT';
160
161
    /**
162
     * Manipulation::WATERMARK_MIDDLE_RIGHT
163
     *
164
     * Watermark middle right position.
165
     *
166
     * @var string
167
     */
168
    const WATERMARK_MIDDLE_RIGHT = 'MIDDLE_RIGHT';
169
170
    /**
171
     * Manipulation::WATERMARK_MIDDLE_TOP
172
     *
173
     * Watermark middle top position.
174
     *
175
     * @var string
176
     */
177
    const WATERMARK_MIDDLE_TOP = 'MIDDLE_TOP';
178
179
    /**
180
     * Manipulation::WATERMARK_MIDDLE_BOTTOM
181
     *
182
     * Watermark middle bottom position.
183
     *
184
     * @var string
185
     */
186
    const WATERMARK_MIDDLE_BOTTOM = 'MIDDLE_BOTTOM';
187
188
    /**
189
     * Manipulation::WATERMARK_TOP_LEFT
190
     *
191
     * Watermark top left position.
192
     *
193
     * @var string
194
     */
195
    const WATERMARK_TOP_LEFT = 'TOP_LEFT';
196
197
    /**
198
     * Manipulation::WATERMARK_TOP_RIGHT
199
     *
200
     * Watermark top right position.
201
     *
202
     * @var string
203
     */
204
    const WATERMARK_TOP_RIGHT = 'TOP_RIGHT';
205
206
    /**
207
     * Manipulation::WATERMARK_BOTTOM_LEFT
208
     *
209
     * Watermark bottom left position.
210
     *
211
     * @var string
212
     */
213
    const WATERMARK_BOTTOM_LEFT = 'BOTTOM_LEFT';
214
215
    /**
216
     * Manipulation::WATERMARK_BOTTOM_RIGHT
217
     *
218
     * Watermark bottom right position.
219
     *
220
     * @var string
221
     */
222
    const WATERMARK_BOTTOM_RIGHT = 'BOTTOM_RIGHT';
223
224
    /**
225
     * Manipulation::$config
226
     *
227
     * Manipulation image config.
228
     *
229
     * @var Config
230
     */
231
    protected $config;
232
233
    /**
234
     * Manipulation::$driver
235
     *
236
     * Manipulation image driver.
237
     *
238
     * @var AbstractDriver
239
     */
240
    protected $driver;
241
242
    // ------------------------------------------------------------------------
243
244
    /**
245
     * Manipulation::__construct
246
     *
247
     * @param \O2System\Image\DataStructures\Config $config
248
     */
249
    public function __construct(Config $config = null)
250
    {
251
        language()
252
            ->addFilePath(__DIR__ . DIRECTORY_SEPARATOR)
253
            ->loadFile('image');
254
255
        $this->config = is_null($config) ? new Config() : $config;
256
257
        if ($this->config->offsetExists('driver')) {
258
            $this->loadDriver($this->config->driver);
0 ignored issues
show
Bug Best Practice introduced by
The property driver does not exist on O2System\Image\DataStructures\Config. Since you implemented __get, consider adding a @property annotation.
Loading history...
259
        }
260
    }
261
262
    // ------------------------------------------------------------------------
263
264
    /**
265
     * Manipulation::loadDriver
266
     *
267
     * Internal driver loader.
268
     *
269
     * @param string $driverOffset Driver offset name.
270
     *
271
     * @return bool
272
     */
273
    protected function loadDriver($driverOffset)
274
    {
275
        $driverClassName = '\O2System\Image\Drivers\\' . ucfirst($driverOffset) . 'Driver';
276
277
        if (class_exists($driverClassName)) {
278
            if ($this->config->offsetExists($driverOffset)) {
279
                $config = $this->config[ $driverOffset ];
280
            } else {
281
                $config = $this->config->getArrayCopy();
282
            }
283
284
            if (isset($config[ 'engine' ])) {
285
                unset($config[ 'engine' ]);
286
            }
287
288
            $this->driver = new $driverClassName();
289
290
            return true;
291
        }
292
293
        return false;
294
    }
295
296
    // ------------------------------------------------------------------------
297
298
    /**
299
     * Manipulation::setDriver
300
     *
301
     * Manually set image manipulation library driver.
302
     *
303
     * @param \O2System\Image\Abstracts\AbstractDriver $imageDriver
304
     *
305
     * @return static
306
     */
307
    public function setDriver(AbstractDriver $imageDriver)
308
    {
309
        $this->driver = $imageDriver;
310
311
        return $this;
312
    }
313
314
    // ------------------------------------------------------------------------
315
316
    /**
317
     * Manipulation::setImageFile
318
     *
319
     * Sets image for manipulation.
320
     *
321
     * @param string $imageFilePath Existing image file path.
322
     *
323
     * @return static
324
     * @throws \O2System\Spl\Exceptions\Runtime\FileNotFoundException
325
     */
326
    public function setImageFile($imageFilePath)
327
    {
328
        if ( ! $this->driver->setSourceImage($imageFilePath)) {
329
            throw new FileNotFoundException('IMAGE_E_FILE_NOT_FOUND', 0, [$imageFilePath]);
330
        }
331
332
        // Create image source resource
333
        $this->driver->createFromSource();
334
335
        return $this;
336
    }
337
338
    // ------------------------------------------------------------------------
339
340
    /**
341
     * Manipulation::setImageUrl
342
     *
343
     * @param string $imageUrl
344
     *
345
     * @return static
346
     * @throws \O2System\Spl\Exceptions\Runtime\FileNotFoundException
347
     */
348
    public function setImageUrl($imageUrl)
349
    {
350
        if (false === ($imageString = file_get_contents($imageUrl))) {
351
            throw new FileNotFoundException('IMAGE_E_URL_INVALID', 0, [$imageUrl]);
352
        }
353
354
        // Create image source resource
355
        $this->driver->createFromString($imageString);
356
357
        return $this;
358
    }
359
360
    // ------------------------------------------------------------------------
361
362
    /**
363
     * Manipulation::setImageString
364
     *
365
     * @param string $imageString Image string.
366
     * @param bool   $base64      Use base64_decode to decode the image string.
367
     *
368
     * @return static
369
     * @throws \O2System\Spl\Exceptions\Runtime\FileNotFoundException
370
     */
371
    public function setImageString($imageString, $base64 = false)
372
    {
373
        if ($base64) {
374
            if (false === ($imageString = base64_decode($imageString, true))) {
375
                throw new FileNotFoundException('IMAGE_E_STRING_INVALID');
376
            }
377
        }
378
379
        // Create image source resource
380
        $this->driver->createFromString($imageString);
381
382
        return $this;
383
    }
384
385
    // ------------------------------------------------------------------------
386
387
    /**
388
     * Manipulation::rotateImage
389
     *
390
     * Rotate an image.
391
     *
392
     * @param int $degrees Image rotation degrees.
393
     *
394
     * @return bool
395
     */
396
    public function rotateImage($degrees)
397
    {
398
        if (is_int($degrees)) {
0 ignored issues
show
introduced by
The condition is_int($degrees) is always true.
Loading history...
399
            $this->driver->rotate($degrees);
400
401
            return true;
402
        }
403
404
        return false;
405
    }
406
407
    // ------------------------------------------------------------------------
408
409
    /**
410
     * Manipulation::flipImage
411
     *
412
     * Flip an image.
413
     *
414
     * @param int $axis Image flip axis.
415
     *
416
     * @return bool
417
     */
418
    public function flipImage($axis)
419
    {
420
        if (in_array($axis, [self::FLIP_HORIZONTAL, self::FLIP_VERTICAL, self::FLIP_BOTH])) {
421
422
            $this->driver->flip($axis);
423
424
            return true;
425
        }
426
427
        return false;
428
    }
429
430
    // ------------------------------------------------------------------------
431
432
    /**
433
     * Manipulation::resizeImage
434
     *
435
     * Scale an image using the given new width and height
436
     *
437
     * @param int  $newWidth  The width to scale the image to.
438
     * @param int  $newHeight The height to scale the image to.
439
     * @param bool $crop      The image autocrop
440
     *
441
     * @return bool
442
     */
443
    public function resizeImage($newWidth, $newHeight, $crop = false)
444
    {
445
        $newWidth = intval($newWidth);
446
        $newHeight = intval($newHeight);
447
        $resampleImageFile = $this->driver->getSourceImageFile();
448
        $resampleDimension = $resampleImageFile->getDimension();
449
        $resampleDimension->maintainAspectRatio = $this->config->offsetGet('maintainAspectRatio');
450
451
        if ($newWidth == $newHeight) {
452
            $this->driver->setResampleImage($resampleImageFile->withDimension(
453
                $resampleDimension
454
                    ->withOrientation('SQUARE')
455
                    ->withFocus('CENTER')
456
                    ->withSize($newWidth, $newHeight)
457
            ));
458
459
            return $this->driver->resize(true);
0 ignored issues
show
Unused Code introduced by
The call to O2System\Image\Abstracts\AbstractDriver::resize() has too many arguments starting with true. ( Ignorable by Annotation )

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

459
            return $this->driver->/** @scrutinizer ignore-call */ resize(true);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
460
        } else {
461
            $this->driver->setResampleImage($resampleImageFile->withDimension(
462
                $resampleDimension
463
                    ->withDirective($this->config->offsetGet('scaleDirective'))
464
                    ->withOrientation($this->config->offsetGet('orientation'))
465
                    ->withFocus($this->config->offsetGet('focus'))
466
                    ->withSize($newWidth, $newHeight)
467
            ));
468
469
            return $this->driver->resize($crop);
470
        }
471
    }
472
473
    // ------------------------------------------------------------------------
474
475
    /**
476
     * Manipulation::scaleImage
477
     *
478
     * Scale an image using the percentage image scale.
479
     *
480
     * @param int $newScale The percentage to scale the image to.
481
     *
482
     * @return bool
483
     */
484
    public function scaleImage($newScale)
485
    {
486
        $resampleImageFile = $this->driver->getSourceImageFile();
487
        $resampleDimension = $resampleImageFile->getDimension();
488
        $resampleDimension->maintainAspectRatio = $this->config->offsetGet('maintainAspectRatio');
489
490
        $this->driver->setResampleImage($resampleImageFile->withDimension(
491
            $resampleDimension
492
                ->withScale($newScale)
493
        ));
494
495
        return $this->driver->scale();
496
    }
497
498
    // ------------------------------------------------------------------------
499
500
    /**
501
     * Manipulation::watermarkImage
502
     *
503
     * Watermark an image using Text or Overlay.
504
     *
505
     * @param \O2System\Image\Abstracts\AbstractWatermark $watermark
506
     */
507
    public function watermarkImage(AbstractWatermark $watermark)
508
    {
509
        $this->driver->watermark($watermark);
0 ignored issues
show
Bug introduced by
The method watermark() does not exist on O2System\Image\Abstracts\AbstractDriver. Since it exists in all sub-types, consider adding an abstract or default implementation to O2System\Image\Abstracts\AbstractDriver. ( Ignorable by Annotation )

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

509
        $this->driver->/** @scrutinizer ignore-call */ 
510
                       watermark($watermark);
Loading history...
510
    }
511
512
    // ------------------------------------------------------------------------
513
514
    /**
515
     * Manipulation::cropImage
516
     *
517
     * Crop an image using new Dimension.
518
     *
519
     * @param \O2System\Image\Dimension $dimension
520
     */
521
    public function cropImage(Dimension $dimension)
522
    {
523
        $this->driver->crop($dimension);
0 ignored issues
show
Bug introduced by
The method crop() does not exist on O2System\Image\Abstracts\AbstractDriver. Since it exists in all sub-types, consider adding an abstract or default implementation to O2System\Image\Abstracts\AbstractDriver. ( Ignorable by Annotation )

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

523
        $this->driver->/** @scrutinizer ignore-call */ crop($dimension);
Loading history...
524
    }
525
526
    // ------------------------------------------------------------------------
527
528
    /**
529
     * Manipulation::getBlobImage
530
     *
531
     * Gets image blob string.
532
     *
533
     * @return string
534
     */
535
    public function getBlobImage()
536
    {
537
        return $this->driver->blob($this->config->offsetGet('quality'));
538
    }
539
540
    // ------------------------------------------------------------------------
541
542
    /**
543
     * Manipulation::displayImage
544
     *
545
     * Display an image.
546
     *
547
     * @return void
548
     */
549
    public function displayImage($quality = null, $mime = null)
550
    {
551
        $quality = empty($quality) ? $this->config->offsetGet('quality') : $quality;
552
553
        $filename = pathinfo($this->driver->getSourceImageFile()->getBasename(), PATHINFO_FILENAME);
554
        $extension = pathinfo($this->driver->getSourceImageFile()->getBasename(), PATHINFO_EXTENSION);
555
556
        if (empty($mime)) {
557
            $mime = $this->driver->getSourceImageFile()->getMime();
558
            $mime = is_array($mime) ? $mime[ 0 ] : $mime;
559
560
            $extension = $this->driver->getMimeExtension($mime);
561
        }
562
563
        if ($this->saveImage($tempImageFilePath = rtrim(sys_get_temp_dir(),
564
                DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $filename . '.' . $extension,
0 ignored issues
show
Bug introduced by
Are you sure $extension of type false|mixed|string can be used in concatenation? ( Ignorable by Annotation )

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

564
                DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $filename . '.' . /** @scrutinizer ignore-type */ $extension,
Loading history...
565
            $quality)
566
        ) {
567
            $imageBlob = readfile($tempImageFilePath);
568
            unlink($tempImageFilePath);
569
        }
570
571
        header('Content-Transfer-Encoding: binary');
572
        header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
573
        header('Content-Disposition: filename=' . $filename . '.' . $extension);
574
        header('Content-Type: ' . $mime);
575
576
        echo $imageBlob;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $imageBlob does not seem to be defined for all execution paths leading up to this point.
Loading history...
577
        exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
578
    }
579
580
    // ------------------------------------------------------------------------
581
582
    /**
583
     * Manipulation::saveImage
584
     *
585
     * Save an manipulated image into new image file.
586
     *
587
     * @param string $saveImageFilePath Save image file path.
588
     *
589
     * @return bool
590
     */
591
    public function saveImage($saveImageFilePath, $quality = null)
592
    {
593
        $quality = empty($quality) ? $this->config->offsetGet('quality') : $quality;
594
        $optimizerConfig = $this->config->offsetGet('optimizer');
595
596
        if ($this->driver->save($saveImageFilePath, $quality)) {
597
            if ($optimizerConfig === 'default') {
598
                $optimizer = new Optimizer();
599
                $optimizer->optimize($saveImageFilePath);
600
            } elseif ( ! empty($optimizerConfig[ 'factory' ])) {
601
                $factory = $optimizerConfig[ 'factory' ];
602
                $optimizer = new Optimizer();
603
604
                switch ($factory) {
605
                    case 'imageoptim';
606
                        $factory = new Imageoptim();
607
                        $factory->setUsername($optimizerConfig[ 'username' ]);
608
                        $optimizer->setImageFactory($factory);
609
                        break;
610
                }
611
612
                $optimizer->optimize($saveImageFilePath);
613
            }
614
615
            return true;
616
        }
617
618
        return false;
619
    }
620
}