Test Failed
Push — develop ( ff58ad...b8f9b2 )
by steve
13:44 queued 12s
created

ImageManager::processImage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 2
dl 0
loc 8
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @link http://www.newicon.net/neon
4
 * @copyright Copyright (c) 2017 Newicon Ltd
5
 * @license http://www.newicon.net/neon/license/
6
 * @author Steve O'Brien <[email protected]> 06/05/2017
7
 * @package neon
8
 */
9
10
namespace neon\firefly\services;
11
12
use \Intervention\Image\ImageManager as InterventionImageManager;
13
use \Intervention\Image\Exception\NotReadableException;
14
use \Intervention\Image\Image as Image;
15
use \neon\core\helpers\Arr;
16
use neon\core\helpers\Hash;
17
use yii\web\HttpException;
18
19
class ImageManager
20
{
21
	/**
22
	 *
23
	 * @param string $source - Source to create an image from. Can be one of the following:
24
	 * string - A firefly uuid
25
	 * string - Path of the image in filesystem.
26
	 * string - URL of an image (allow_url_fopen must be enabled).
27
	 * string - Binary image data.
28
	 * string - Data-URL encoded image data.
29
	 * string - Base64 encoded image data.
30
	 * resource - PHP resource of type gd. (when using GD driver)
31
	 * object - Imagick instance (when using Imagick driver)
32
	 * object - Intervention\Image\Image instance
33
	 * object - SplFileInfo instance (To handle file uploads via Symfony\Component\HttpFoundation\File\UploadedFile)
34
	 * @throws HttpException if $image is a firefly uuid and is not found
35
	 * @return mixed
36
	 */
37
	public function process($source, $params)
38
	{
39
		// get firefly image if the source is a firefly id
40
		if (Hash::isUuid64($source)) {
41
			if (!neon()->firefly->fileManager->exists($source))
42
				throw new HttpException(404);
43
			$meta = neon()->firefly->fileManager->getMeta($source);
44
			if ($meta['mime_type'] == 'image/svg')
45
				return neon()->firefly->fileManager->read($source);
46
			$source = neon()->firefly->fileManager->readStream($source);
47
		}
48
		$manager = new InterventionImageManager();
49
		$image = $manager->make($source);
50
		$this->processImage($image, $params);
51
		return $image->response(null, Arr::get($params, 'q', 90));
52
	}
53
54
	/**
55
	 * Process the image based on passed in params
56
	 * @param Image $image
57
	 * @param array $params - url params passed (array format)
58
	 */
59
	public function processImage(Image & $image, $params)
60
	{
61
		$image->interlace();
62
		$this->imageResize($image, $params);
63
		$this->imageRotate($image, $params);
64
		$this->imageFlip($image, $params);
65
		$this->imageFilter($image, $params);
66
		$this->imageCrop($image, $params);
67
	}
68
69
	/**
70
	 * Process the image resize based on passed $params (w,h,fit | width,height)
71
	 * @param Image $image - The Intervention image object
72
	 * @param array $params - url params passed (array format)
73
	 */
74
	public function imageResize(Image & $image, $params)
75
	{
76
		// Get url params
77
		$width = Arr::get($params, 'w', Arr::get($params, 'width', null));
78
		$height = Arr::get($params, 'h', Arr::get($params, 'height', null));
79
		list($width, $height) = $this->resolveMissingDimensions($image, $width, $height);
80
		$pd = (double) Arr::get($params, 'pd', 1);
81
82
		if (Arr::get($params, 'fit', false)) {
83
			// add callback functionality to retain maximal original image size
84
			$image->fit($width, $height, function ($constraint) {
85
				$constraint->aspectRatio();
86
				$constraint->upsize();
87
			}, $params['fit']);
88
		} elseif ($width || $height) {
89
			$width = $width * $pd;
90
			$height = $height * $pd;
91
			$image->resize($width, $height, function ($constraint) {
92
				$constraint->aspectRatio();
93
				$constraint->upsize();
94
			});
95
		}
96
	}
97
	
98
	/**
99
	 * Rotate the image if params contains rotate
100
	 * @param Image $image - The Intervention image object
101
	 * @param array $params - url params passed (array format)
102
	 */
103
	public function imageRotate(Image & $image, $params)
104
	{
105
		$rotate = Arr::get($params, 'rotate', false);
106
		if ($rotate) $image->rotate($rotate);
107
	}
108
109
	/**
110
	 * Flip the image if params contains flip info (flip=v)
111
	 * @param Image $image - The Intervention image object
112
	 * @param array $params - url params passed (array format)
113
	 */
114
	public function imageFlip(Image & $image, $params)
115
	{
116
		$flip = Arr::get($params, 'flip', false);
117
		if ($flip !== false) {
118
			// flip horizontal
119
			if ($flip === 'v') {
120
				$image->flip('v');
121
			} else {
122
				// by default it will flip horizontally
123
				$image->flip('h');
124
			}
125
		}
126
	}
127
128
	/**
129
	 * Apply filters to the image if params contains filter info (flip=v)
130
	 * @param Image $image - The Intervention image object
131
	 * @param array $params - url params passed (array format)
132
	 */
133
	public function imageFilter(Image & $image, $params)
134
	{
135
		$filter = Arr::get($params, 'filter', false);
136
		if ($filter) {
137
			$filters = explode(',',$filter);
138
			if (in_array('greyscale', $filters, true)) {
139
				$image->greyscale();
140
			}
141
			if (in_array('sepia', $filters, true)) {
142
				$this->runSepiaFilter($image);
143
			}
144
			if (in_array('invert', $filters, true)) {
145
				$image->invert();
146
			}
147
		}
148
	}
149
150
	/**
151
	 * Apply crop to the image if params contains crop params info
152
	 * @param Image $image - The Intervention image object
153
	 * @param array $params - url params passed (array format)
154
	 */
155
	public function imageCrop(Image & $image, $params)
156
	{
157
		$crop = Arr::get($params, 'crop', false);
158
		if ($crop !== false) {
159
			if (is_string($crop)) {
160
				$bits = explode(',', $crop);
161
				$w = Arr::get($bits, 0, null);
162
				$h = Arr::get($bits, 1, null);
163
				$x = Arr::get($bits, 2, null);
164
				$y = Arr::get($bits, 3, null);
165
			}
166
			if (is_array($crop)) {
167
				$w = Arr::get($crop, 'width', null);
168
				$h = Arr::get($crop, 'height', null);
169
				$x = Arr::get($crop, 'x', null);
170
				$y = Arr::get($crop, 'y', null);
171
			}
172
			if ($w == 0 && $h == 0 && $x == 0 && $y ==0) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $x does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $h does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $y does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $w does not seem to be defined for all execution paths leading up to this point.
Loading history...
173
				return $image;
174
			}
175
			$image->crop($w, $h, $x, $y);
176
			$manager = new InterventionImageManager();
177
			$bg = $manager->canvas($w, $h, array(255, 255, 255, 0));
178
			// Fill up the blank spaces with transparent color
179
			$image = $bg->insert($image, 'center');
180
		}
181
	}
182
183
	/**
184
	 * Resolve missing image dimensions.
185
	 * @param  Image        $image  The source image.
186
	 * @param  integer|null $width  The image width.
187
	 * @param  integer|null $height The image height.
188
	 * @return integer[]    The resolved width and height.
189
	 */
190
	public function resolveMissingDimensions(Image & $image, $width, $height)
191
	{
192
		if (is_null($width) and is_null($height)) {
193
			$width = $image->width();
194
			$height = $image->height();
195
		}
196
197
		if (is_null($width)) {
198
			$width = $height * ($image->width() / $image->height());
199
		}
200
201
		if (is_null($height)) {
202
			$height = $width / ($image->width() / $image->height());
203
		}
204
205
		return [
206
			(int) $width,
207
			(int) $height,
208
		];
209
	}
210
211
	/**
212
	 * Perform sepia manipulation.
213
	 * @param  Image $image The source image.
214
	 * @return Image The manipulated image.
215
	 */
216
	public function runSepiaFilter(Image & $image)
217
	{
218
		$image->greyscale();
219
		$image->brightness(-10);
220
		$image->contrast(10);
221
		$image->colorize(38, 27, 12);
222
		$image->brightness(-10);
223
		$image->contrast(10);
224
		return $image;
225
	}
226
227
	/**
228
	 * @return string
229
	 */
230
	public function getPlaceholderImageContents()
231
	{
232
		// should be configurable by settings somewhere
233
		return file_get_contents(dirname(__DIR__).'/assets/placeholder.jpg');
234
	}
235
236
	public function getNotReadableImageContents()
237
	{
238
		// should be configurable by settings somewhere
239
		return file_get_contents(dirname(__DIR__).'/assets/placeholder-broken.png');
240
	}
241
}
242