Completed
Pull Request — master (#8020)
by Julius
22:02
created
lib/private/Avatar.php 1 patch
Indentation   +385 added lines, -385 removed lines patch added patch discarded remove patch
@@ -46,390 +46,390 @@
 block discarded – undo
46 46
  */
47 47
 
48 48
 class Avatar implements IAvatar {
49
-	/** @var ISimpleFolder */
50
-	private $folder;
51
-	/** @var IL10N */
52
-	private $l;
53
-	/** @var User */
54
-	private $user;
55
-	/** @var ILogger  */
56
-	private $logger;
57
-	/** @var IConfig */
58
-	private $config;
59
-
60
-	/**
61
-	 * constructor
62
-	 *
63
-	 * @param ISimpleFolder $folder The folder where the avatars are
64
-	 * @param IL10N $l
65
-	 * @param User $user
66
-	 * @param ILogger $logger
67
-	 * @param IConfig $config
68
-	 */
69
-	public function __construct(ISimpleFolder $folder,
70
-								IL10N $l,
71
-								$user,
72
-								ILogger $logger,
73
-								IConfig $config) {
74
-		$this->folder = $folder;
75
-		$this->l = $l;
76
-		$this->user = $user;
77
-		$this->logger = $logger;
78
-		$this->config = $config;
79
-	}
80
-
81
-	/**
82
-	 * @inheritdoc
83
-	 */
84
-	public function get ($size = 64) {
85
-		try {
86
-			$file = $this->getFile($size);
87
-		} catch (NotFoundException $e) {
88
-			return false;
89
-		}
90
-
91
-		$avatar = new OC_Image();
92
-		$avatar->loadFromData($file->getContent());
93
-		return $avatar;
94
-	}
95
-
96
-	/**
97
-	 * Check if an avatar exists for the user
98
-	 *
99
-	 * @return bool
100
-	 */
101
-	public function exists() {
102
-
103
-		return $this->folder->fileExists('avatar.jpg') || $this->folder->fileExists('avatar.png');
104
-	}
105
-
106
-	/**
107
-	 * sets the users avatar
108
-	 * @param IImage|resource|string $data An image object, imagedata or path to set a new avatar
109
-	 * @throws \Exception if the provided file is not a jpg or png image
110
-	 * @throws \Exception if the provided image is not valid
111
-	 * @throws NotSquareException if the image is not square
112
-	 * @return void
113
-	*/
114
-	public function set ($data) {
115
-
116
-		if($data instanceOf IImage) {
117
-			$img = $data;
118
-			$data = $img->data();
119
-		} else {
120
-			$img = new OC_Image();
121
-			if (is_resource($data) && get_resource_type($data) === "gd") {
122
-				$img->setResource($data);
123
-			} elseif(is_resource($data)) {
124
-				$img->loadFromFileHandle($data);
125
-			} else {
126
-				try {
127
-					// detect if it is a path or maybe the images as string
128
-					$result = @realpath($data);
129
-					if ($result === false || $result === null) {
130
-						$img->loadFromData($data);
131
-					} else {
132
-						$img->loadFromFile($data);
133
-					}
134
-				} catch (\Error $e) {
135
-					$img->loadFromData($data);
136
-				}
137
-			}
138
-		}
139
-		$type = substr($img->mimeType(), -3);
140
-		if ($type === 'peg') {
141
-			$type = 'jpg';
142
-		}
143
-		if ($type !== 'jpg' && $type !== 'png') {
144
-			throw new \Exception($this->l->t('Unknown filetype'));
145
-		}
146
-
147
-		if (!$img->valid()) {
148
-			throw new \Exception($this->l->t('Invalid image'));
149
-		}
150
-
151
-		if (!($img->height() === $img->width())) {
152
-			throw new NotSquareException($this->l->t('Avatar image is not square'));
153
-		}
154
-
155
-		$this->remove();
156
-		$file = $this->folder->newFile('avatar.'.$type);
157
-		$file->putContent($data);
158
-
159
-		try {
160
-			$generated = $this->folder->getFile('generated');
161
-			$this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', 'false');
162
-			$generated->delete();
163
-		} catch (NotFoundException $e) {
164
-			//
165
-		}
166
-		$this->user->triggerChange('avatar', $file);
167
-	}
168
-
169
-	/**
170
-	 * remove the users avatar
171
-	 * @return void
172
-	*/
173
-	public function remove () {
174
-		$avatars = $this->folder->getDirectoryListing();
175
-
176
-		$this->config->setUserValue($this->user->getUID(), 'avatar', 'version',
177
-			(int)$this->config->getUserValue($this->user->getUID(), 'avatar', 'version', 0) + 1);
178
-
179
-		foreach ($avatars as $avatar) {
180
-			$avatar->delete();
181
-		}
182
-		$this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', 'true');
183
-		$this->user->triggerChange('avatar', '');
184
-	}
185
-
186
-	/**
187
-	 * @inheritdoc
188
-	 */
189
-	public function getFile($size) {
190
-		try {
191
-			$ext = $this->getExtension();
192
-		} catch (NotFoundException $e) {
193
-			$data = $this->generateAvatar($this->user->getDisplayName(), 1024);
194
-			$avatar = $this->folder->newFile('avatar.png');
195
-			$avatar->putContent($data);
196
-			$ext = 'png';
197
-
198
-			$this->folder->newFile('generated');
199
-			$this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', 'true');
200
-		}
201
-
202
-		if ($size === -1) {
203
-			$path = 'avatar.' . $ext;
204
-		} else {
205
-			$path = 'avatar.' . $size . '.' . $ext;
206
-		}
207
-
208
-		try {
209
-			$file = $this->folder->getFile($path);
210
-		} catch (NotFoundException $e) {
211
-			if ($size <= 0) {
212
-				throw new NotFoundException;
213
-			}
214
-
215
-			if ($this->folder->fileExists('generated')) {
216
-				$data = $this->generateAvatar($this->user->getDisplayName(), $size);
217
-
218
-			} else {
219
-				$avatar = new OC_Image();
220
-				/** @var ISimpleFile $file */
221
-				$file = $this->folder->getFile('avatar.' . $ext);
222
-				$avatar->loadFromData($file->getContent());
223
-				$avatar->resize($size);
224
-				$data = $avatar->data();
225
-			}
226
-
227
-			try {
228
-				$file = $this->folder->newFile($path);
229
-				$file->putContent($data);
230
-			} catch (NotPermittedException $e) {
231
-				$this->logger->error('Failed to save avatar for ' . $this->user->getUID());
232
-				throw new NotFoundException();
233
-			}
234
-
235
-		}
236
-
237
-		if($this->config->getUserValue($this->user->getUID(), 'avatar', 'generated', null) === null) {
238
-			$generated = $this->folder->fileExists('generated') ? 'true' : 'false';
239
-			$this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', $generated);
240
-		}
241
-
242
-		return $file;
243
-	}
244
-
245
-	/**
246
-	 * Get the extension of the avatar. If there is no avatar throw Exception
247
-	 *
248
-	 * @return string
249
-	 * @throws NotFoundException
250
-	 */
251
-	private function getExtension() {
252
-		if ($this->folder->fileExists('avatar.jpg')) {
253
-			return 'jpg';
254
-		} elseif ($this->folder->fileExists('avatar.png')) {
255
-			return 'png';
256
-		}
257
-		throw new NotFoundException;
258
-	}
259
-
260
-	/**
261
-	 * @param string $userDisplayName
262
-	 * @param int $size
263
-	 * @return string
264
-	 */
265
-	private function generateAvatar($userDisplayName, $size) {
266
-		$text = strtoupper(substr($userDisplayName, 0, 1));
267
-		$backgroundColor = $this->avatarBackgroundColor($userDisplayName);
268
-
269
-		$im = imagecreatetruecolor($size, $size);
270
-		$background = imagecolorallocate($im, $backgroundColor[0], $backgroundColor[1], $backgroundColor[2]);
271
-		$white = imagecolorallocate($im, 255, 255, 255);
272
-		imagefilledrectangle($im, 0, 0, $size, $size, $background);
273
-
274
-		$font = __DIR__ . '/../../core/fonts/OpenSans-Semibold.woff';
275
-
276
-		$fontSize = $size * 0.4;
277
-		$box = imagettfbbox($fontSize, 0, $font, $text);
278
-
279
-		$x = ($size - ($box[2] - $box[0])) / 2;
280
-		$y = ($size - ($box[1] - $box[7])) / 2;
281
-		$x += 1;
282
-		$y -= $box[7];
283
-		imagettftext($im, $fontSize, 0, $x, $y, $white, $font, $text);
284
-
285
-		ob_start();
286
-		imagepng($im);
287
-		$data = ob_get_contents();
288
-		ob_end_clean();
289
-
290
-		return $data;
291
-	}
292
-
293
-	/**
294
-	 * @param int $r
295
-	 * @param int $g
296
-	 * @param int $b
297
-	 * @return double[] Array containing h s l in [0, 1] range
298
-	 */
299
-	private function rgbToHsl($r, $g, $b) {
300
-		$r /= 255.0;
301
-		$g /= 255.0;
302
-		$b /= 255.0;
303
-
304
-		$max = max($r, $g, $b);
305
-		$min = min($r, $g, $b);
306
-
307
-
308
-		$h = ($max + $min) / 2.0;
309
-		$l = ($max + $min) / 2.0;
310
-
311
-		if($max === $min) {
312
-			$h = $s = 0; // Achromatic
313
-		} else {
314
-			$d = $max - $min;
315
-			$s = $l > 0.5 ? $d / (2 - $max - $min) : $d / ($max + $min);
316
-			switch($max) {
317
-				case $r:
318
-					$h = ($g - $b) / $d + ($g < $b ? 6 : 0);
319
-					break;
320
-				case $g:
321
-					$h = ($b - $r) / $d + 2.0;
322
-					break;
323
-				case $b:
324
-					$h = ($r - $g) / $d + 4.0;
325
-					break;
326
-			}
327
-			$h /= 6.0;
328
-		}
329
-		return [$h, $s, $l];
330
-
331
-	}
332
-
333
-	/**
334
-	 * @param string $text
335
-	 * @return int[] Array containting r g b in the range [0, 255]
336
-	 */
337
-	private function avatarBackgroundColor($text) {
338
-		$hash = preg_replace('/[^0-9a-f]+/', '', $text);
339
-
340
-		$hash = md5($hash);
341
-		$hashChars = str_split($hash);
342
-
343
-
344
-		// Init vars
345
-		$result = ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'];
346
-		$rgb = [0, 0, 0];
347
-		$sat = 0.70;
348
-		$lum = 0.68;
349
-		$modulo = 16;
350
-
351
-
352
-		// Splitting evenly the string
353
-		foreach($hashChars as  $i => $char) {
354
-			$result[$i % $modulo] .= intval($char, 16);
355
-		}
356
-
357
-		// Converting our data into a usable rgb format
358
-		// Start at 1 because 16%3=1 but 15%3=0 and makes the repartition even
359
-		for($count = 1; $count < $modulo; $count++) {
360
-			$rgb[$count%3] += (int)$result[$count];
361
-		}
362
-
363
-		// Reduce values bigger than rgb requirements
364
-		$rgb[0] %= 255;
365
-		$rgb[1] %= 255;
366
-		$rgb[2] %= 255;
367
-
368
-		$hsl = $this->rgbToHsl($rgb[0], $rgb[1], $rgb[2]);
369
-
370
-		// Classic formula to check the brightness for our eye
371
-		// If too bright, lower the sat
372
-		$bright = sqrt(0.299 * ($rgb[0] ** 2) + 0.587 * ($rgb[1] ** 2) + 0.114 * ($rgb[2] ** 2));
373
-		if ($bright >= 200) {
374
-			$sat = 0.60;
375
-		}
376
-
377
-		return $this->hslToRgb($hsl[0], $sat, $lum);
378
-	}
379
-
380
-	/**
381
-	 * @param double $h Hue in range [0, 1]
382
-	 * @param double $s Saturation in range [0, 1]
383
-	 * @param double $l Lightness in range [0, 1]
384
-	 * @return int[] Array containing r g b in the range [0, 255]
385
-	 */
386
-	private function hslToRgb($h, $s, $l){
387
-		$hue2rgb = function ($p, $q, $t){
388
-			if($t < 0) {
389
-				$t += 1;
390
-			}
391
-			if($t > 1) {
392
-				$t -= 1;
393
-			}
394
-			if($t < 1/6) {
395
-				return $p + ($q - $p) * 6 * $t;
396
-			}
397
-			if($t < 1/2) {
398
-				return $q;
399
-			}
400
-			if($t < 2/3) {
401
-				return $p + ($q - $p) * (2/3 - $t) * 6;
402
-			}
403
-			return $p;
404
-		};
405
-
406
-		if($s === 0){
407
-			$r = $l;
408
-			$g = $l;
409
-			$b = $l; // achromatic
410
-		}else{
411
-			$q = $l < 0.5 ? $l * (1 + $s) : $l + $s - $l * $s;
412
-			$p = 2 * $l - $q;
413
-			$r = $hue2rgb($p, $q, $h + 1/3);
414
-			$g = $hue2rgb($p, $q, $h);
415
-			$b = $hue2rgb($p, $q, $h - 1/3);
416
-		}
417
-
418
-		return array(round($r * 255), round($g * 255), round($b * 255));
419
-	}
420
-
421
-	public function userChanged($feature, $oldValue, $newValue) {
422
-		// We only change the avatar on display name changes
423
-		if ($feature !== 'displayName') {
424
-			return;
425
-		}
426
-
427
-		// If the avatar is not generated (so an uploaded image) we skip this
428
-		if (!$this->folder->fileExists('generated')) {
429
-			return;
430
-		}
431
-
432
-		$this->remove();
433
-	}
49
+    /** @var ISimpleFolder */
50
+    private $folder;
51
+    /** @var IL10N */
52
+    private $l;
53
+    /** @var User */
54
+    private $user;
55
+    /** @var ILogger  */
56
+    private $logger;
57
+    /** @var IConfig */
58
+    private $config;
59
+
60
+    /**
61
+     * constructor
62
+     *
63
+     * @param ISimpleFolder $folder The folder where the avatars are
64
+     * @param IL10N $l
65
+     * @param User $user
66
+     * @param ILogger $logger
67
+     * @param IConfig $config
68
+     */
69
+    public function __construct(ISimpleFolder $folder,
70
+                                IL10N $l,
71
+                                $user,
72
+                                ILogger $logger,
73
+                                IConfig $config) {
74
+        $this->folder = $folder;
75
+        $this->l = $l;
76
+        $this->user = $user;
77
+        $this->logger = $logger;
78
+        $this->config = $config;
79
+    }
80
+
81
+    /**
82
+     * @inheritdoc
83
+     */
84
+    public function get ($size = 64) {
85
+        try {
86
+            $file = $this->getFile($size);
87
+        } catch (NotFoundException $e) {
88
+            return false;
89
+        }
90
+
91
+        $avatar = new OC_Image();
92
+        $avatar->loadFromData($file->getContent());
93
+        return $avatar;
94
+    }
95
+
96
+    /**
97
+     * Check if an avatar exists for the user
98
+     *
99
+     * @return bool
100
+     */
101
+    public function exists() {
102
+
103
+        return $this->folder->fileExists('avatar.jpg') || $this->folder->fileExists('avatar.png');
104
+    }
105
+
106
+    /**
107
+     * sets the users avatar
108
+     * @param IImage|resource|string $data An image object, imagedata or path to set a new avatar
109
+     * @throws \Exception if the provided file is not a jpg or png image
110
+     * @throws \Exception if the provided image is not valid
111
+     * @throws NotSquareException if the image is not square
112
+     * @return void
113
+     */
114
+    public function set ($data) {
115
+
116
+        if($data instanceOf IImage) {
117
+            $img = $data;
118
+            $data = $img->data();
119
+        } else {
120
+            $img = new OC_Image();
121
+            if (is_resource($data) && get_resource_type($data) === "gd") {
122
+                $img->setResource($data);
123
+            } elseif(is_resource($data)) {
124
+                $img->loadFromFileHandle($data);
125
+            } else {
126
+                try {
127
+                    // detect if it is a path or maybe the images as string
128
+                    $result = @realpath($data);
129
+                    if ($result === false || $result === null) {
130
+                        $img->loadFromData($data);
131
+                    } else {
132
+                        $img->loadFromFile($data);
133
+                    }
134
+                } catch (\Error $e) {
135
+                    $img->loadFromData($data);
136
+                }
137
+            }
138
+        }
139
+        $type = substr($img->mimeType(), -3);
140
+        if ($type === 'peg') {
141
+            $type = 'jpg';
142
+        }
143
+        if ($type !== 'jpg' && $type !== 'png') {
144
+            throw new \Exception($this->l->t('Unknown filetype'));
145
+        }
146
+
147
+        if (!$img->valid()) {
148
+            throw new \Exception($this->l->t('Invalid image'));
149
+        }
150
+
151
+        if (!($img->height() === $img->width())) {
152
+            throw new NotSquareException($this->l->t('Avatar image is not square'));
153
+        }
154
+
155
+        $this->remove();
156
+        $file = $this->folder->newFile('avatar.'.$type);
157
+        $file->putContent($data);
158
+
159
+        try {
160
+            $generated = $this->folder->getFile('generated');
161
+            $this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', 'false');
162
+            $generated->delete();
163
+        } catch (NotFoundException $e) {
164
+            //
165
+        }
166
+        $this->user->triggerChange('avatar', $file);
167
+    }
168
+
169
+    /**
170
+     * remove the users avatar
171
+     * @return void
172
+     */
173
+    public function remove () {
174
+        $avatars = $this->folder->getDirectoryListing();
175
+
176
+        $this->config->setUserValue($this->user->getUID(), 'avatar', 'version',
177
+            (int)$this->config->getUserValue($this->user->getUID(), 'avatar', 'version', 0) + 1);
178
+
179
+        foreach ($avatars as $avatar) {
180
+            $avatar->delete();
181
+        }
182
+        $this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', 'true');
183
+        $this->user->triggerChange('avatar', '');
184
+    }
185
+
186
+    /**
187
+     * @inheritdoc
188
+     */
189
+    public function getFile($size) {
190
+        try {
191
+            $ext = $this->getExtension();
192
+        } catch (NotFoundException $e) {
193
+            $data = $this->generateAvatar($this->user->getDisplayName(), 1024);
194
+            $avatar = $this->folder->newFile('avatar.png');
195
+            $avatar->putContent($data);
196
+            $ext = 'png';
197
+
198
+            $this->folder->newFile('generated');
199
+            $this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', 'true');
200
+        }
201
+
202
+        if ($size === -1) {
203
+            $path = 'avatar.' . $ext;
204
+        } else {
205
+            $path = 'avatar.' . $size . '.' . $ext;
206
+        }
207
+
208
+        try {
209
+            $file = $this->folder->getFile($path);
210
+        } catch (NotFoundException $e) {
211
+            if ($size <= 0) {
212
+                throw new NotFoundException;
213
+            }
214
+
215
+            if ($this->folder->fileExists('generated')) {
216
+                $data = $this->generateAvatar($this->user->getDisplayName(), $size);
217
+
218
+            } else {
219
+                $avatar = new OC_Image();
220
+                /** @var ISimpleFile $file */
221
+                $file = $this->folder->getFile('avatar.' . $ext);
222
+                $avatar->loadFromData($file->getContent());
223
+                $avatar->resize($size);
224
+                $data = $avatar->data();
225
+            }
226
+
227
+            try {
228
+                $file = $this->folder->newFile($path);
229
+                $file->putContent($data);
230
+            } catch (NotPermittedException $e) {
231
+                $this->logger->error('Failed to save avatar for ' . $this->user->getUID());
232
+                throw new NotFoundException();
233
+            }
234
+
235
+        }
236
+
237
+        if($this->config->getUserValue($this->user->getUID(), 'avatar', 'generated', null) === null) {
238
+            $generated = $this->folder->fileExists('generated') ? 'true' : 'false';
239
+            $this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', $generated);
240
+        }
241
+
242
+        return $file;
243
+    }
244
+
245
+    /**
246
+     * Get the extension of the avatar. If there is no avatar throw Exception
247
+     *
248
+     * @return string
249
+     * @throws NotFoundException
250
+     */
251
+    private function getExtension() {
252
+        if ($this->folder->fileExists('avatar.jpg')) {
253
+            return 'jpg';
254
+        } elseif ($this->folder->fileExists('avatar.png')) {
255
+            return 'png';
256
+        }
257
+        throw new NotFoundException;
258
+    }
259
+
260
+    /**
261
+     * @param string $userDisplayName
262
+     * @param int $size
263
+     * @return string
264
+     */
265
+    private function generateAvatar($userDisplayName, $size) {
266
+        $text = strtoupper(substr($userDisplayName, 0, 1));
267
+        $backgroundColor = $this->avatarBackgroundColor($userDisplayName);
268
+
269
+        $im = imagecreatetruecolor($size, $size);
270
+        $background = imagecolorallocate($im, $backgroundColor[0], $backgroundColor[1], $backgroundColor[2]);
271
+        $white = imagecolorallocate($im, 255, 255, 255);
272
+        imagefilledrectangle($im, 0, 0, $size, $size, $background);
273
+
274
+        $font = __DIR__ . '/../../core/fonts/OpenSans-Semibold.woff';
275
+
276
+        $fontSize = $size * 0.4;
277
+        $box = imagettfbbox($fontSize, 0, $font, $text);
278
+
279
+        $x = ($size - ($box[2] - $box[0])) / 2;
280
+        $y = ($size - ($box[1] - $box[7])) / 2;
281
+        $x += 1;
282
+        $y -= $box[7];
283
+        imagettftext($im, $fontSize, 0, $x, $y, $white, $font, $text);
284
+
285
+        ob_start();
286
+        imagepng($im);
287
+        $data = ob_get_contents();
288
+        ob_end_clean();
289
+
290
+        return $data;
291
+    }
292
+
293
+    /**
294
+     * @param int $r
295
+     * @param int $g
296
+     * @param int $b
297
+     * @return double[] Array containing h s l in [0, 1] range
298
+     */
299
+    private function rgbToHsl($r, $g, $b) {
300
+        $r /= 255.0;
301
+        $g /= 255.0;
302
+        $b /= 255.0;
303
+
304
+        $max = max($r, $g, $b);
305
+        $min = min($r, $g, $b);
306
+
307
+
308
+        $h = ($max + $min) / 2.0;
309
+        $l = ($max + $min) / 2.0;
310
+
311
+        if($max === $min) {
312
+            $h = $s = 0; // Achromatic
313
+        } else {
314
+            $d = $max - $min;
315
+            $s = $l > 0.5 ? $d / (2 - $max - $min) : $d / ($max + $min);
316
+            switch($max) {
317
+                case $r:
318
+                    $h = ($g - $b) / $d + ($g < $b ? 6 : 0);
319
+                    break;
320
+                case $g:
321
+                    $h = ($b - $r) / $d + 2.0;
322
+                    break;
323
+                case $b:
324
+                    $h = ($r - $g) / $d + 4.0;
325
+                    break;
326
+            }
327
+            $h /= 6.0;
328
+        }
329
+        return [$h, $s, $l];
330
+
331
+    }
332
+
333
+    /**
334
+     * @param string $text
335
+     * @return int[] Array containting r g b in the range [0, 255]
336
+     */
337
+    private function avatarBackgroundColor($text) {
338
+        $hash = preg_replace('/[^0-9a-f]+/', '', $text);
339
+
340
+        $hash = md5($hash);
341
+        $hashChars = str_split($hash);
342
+
343
+
344
+        // Init vars
345
+        $result = ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'];
346
+        $rgb = [0, 0, 0];
347
+        $sat = 0.70;
348
+        $lum = 0.68;
349
+        $modulo = 16;
350
+
351
+
352
+        // Splitting evenly the string
353
+        foreach($hashChars as  $i => $char) {
354
+            $result[$i % $modulo] .= intval($char, 16);
355
+        }
356
+
357
+        // Converting our data into a usable rgb format
358
+        // Start at 1 because 16%3=1 but 15%3=0 and makes the repartition even
359
+        for($count = 1; $count < $modulo; $count++) {
360
+            $rgb[$count%3] += (int)$result[$count];
361
+        }
362
+
363
+        // Reduce values bigger than rgb requirements
364
+        $rgb[0] %= 255;
365
+        $rgb[1] %= 255;
366
+        $rgb[2] %= 255;
367
+
368
+        $hsl = $this->rgbToHsl($rgb[0], $rgb[1], $rgb[2]);
369
+
370
+        // Classic formula to check the brightness for our eye
371
+        // If too bright, lower the sat
372
+        $bright = sqrt(0.299 * ($rgb[0] ** 2) + 0.587 * ($rgb[1] ** 2) + 0.114 * ($rgb[2] ** 2));
373
+        if ($bright >= 200) {
374
+            $sat = 0.60;
375
+        }
376
+
377
+        return $this->hslToRgb($hsl[0], $sat, $lum);
378
+    }
379
+
380
+    /**
381
+     * @param double $h Hue in range [0, 1]
382
+     * @param double $s Saturation in range [0, 1]
383
+     * @param double $l Lightness in range [0, 1]
384
+     * @return int[] Array containing r g b in the range [0, 255]
385
+     */
386
+    private function hslToRgb($h, $s, $l){
387
+        $hue2rgb = function ($p, $q, $t){
388
+            if($t < 0) {
389
+                $t += 1;
390
+            }
391
+            if($t > 1) {
392
+                $t -= 1;
393
+            }
394
+            if($t < 1/6) {
395
+                return $p + ($q - $p) * 6 * $t;
396
+            }
397
+            if($t < 1/2) {
398
+                return $q;
399
+            }
400
+            if($t < 2/3) {
401
+                return $p + ($q - $p) * (2/3 - $t) * 6;
402
+            }
403
+            return $p;
404
+        };
405
+
406
+        if($s === 0){
407
+            $r = $l;
408
+            $g = $l;
409
+            $b = $l; // achromatic
410
+        }else{
411
+            $q = $l < 0.5 ? $l * (1 + $s) : $l + $s - $l * $s;
412
+            $p = 2 * $l - $q;
413
+            $r = $hue2rgb($p, $q, $h + 1/3);
414
+            $g = $hue2rgb($p, $q, $h);
415
+            $b = $hue2rgb($p, $q, $h - 1/3);
416
+        }
417
+
418
+        return array(round($r * 255), round($g * 255), round($b * 255));
419
+    }
420
+
421
+    public function userChanged($feature, $oldValue, $newValue) {
422
+        // We only change the avatar on display name changes
423
+        if ($feature !== 'displayName') {
424
+            return;
425
+        }
426
+
427
+        // If the avatar is not generated (so an uploaded image) we skip this
428
+        if (!$this->folder->fileExists('generated')) {
429
+            return;
430
+        }
431
+
432
+        $this->remove();
433
+    }
434 434
 
435 435
 }
Please login to merge, or discard this patch.