Passed
Push — master ( 6e40c2...2a7498 )
by Morris
12:38 queued 11s
created
lib/private/Avatar/Avatar.php 2 patches
Indentation   +269 added lines, -269 removed lines patch added patch discarded remove patch
@@ -50,278 +50,278 @@
 block discarded – undo
50 50
  */
51 51
 abstract class Avatar implements IAvatar {
52 52
 
53
-	/** @var ILogger  */
54
-	protected $logger;
55
-
56
-	/**
57
-	 * https://github.com/sebdesign/cap-height -- for 500px height
58
-	 * Automated check: https://codepen.io/skjnldsv/pen/PydLBK/
59
-	 * Noto Sans cap-height is 0.715 and we want a 200px caps height size
60
-	 * (0.4 letter-to-total-height ratio, 500*0.4=200), so: 200/0.715 = 280px.
61
-	 * Since we start from the baseline (text-anchor) we need to
62
-	 * shift the y axis by 100px (half the caps height): 500/2+100=350
63
-	 *
64
-	 * @var string
65
-	 */
66
-	private $svgTemplate = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>
53
+    /** @var ILogger  */
54
+    protected $logger;
55
+
56
+    /**
57
+     * https://github.com/sebdesign/cap-height -- for 500px height
58
+     * Automated check: https://codepen.io/skjnldsv/pen/PydLBK/
59
+     * Noto Sans cap-height is 0.715 and we want a 200px caps height size
60
+     * (0.4 letter-to-total-height ratio, 500*0.4=200), so: 200/0.715 = 280px.
61
+     * Since we start from the baseline (text-anchor) we need to
62
+     * shift the y axis by 100px (half the caps height): 500/2+100=350
63
+     *
64
+     * @var string
65
+     */
66
+    private $svgTemplate = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>
67 67
 		<svg width="{size}" height="{size}" version="1.1" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">
68 68
 			<rect width="100%" height="100%" fill="#{fill}"></rect>
69 69
 			<text x="50%" y="350" style="font-weight:normal;font-size:280px;font-family:\'Noto Sans\';text-anchor:middle;fill:#fff">{letter}</text>
70 70
 		</svg>';
71 71
 
72
-	/**
73
-	 * The base avatar constructor.
74
-	 *
75
-	 * @param ILogger $logger The logger
76
-	 */
77
-	public function __construct(ILogger $logger) {
78
-		$this->logger = $logger;
79
-	}
80
-
81
-	/**
82
-	 * Returns the user display name.
83
-	 *
84
-	 * @return string
85
-	 */
86
-	abstract public function getDisplayName(): string;
87
-
88
-	/**
89
-	 * Returns the first letter of the display name, or "?" if no name given.
90
-	 *
91
-	 * @return string
92
-	 */
93
-	private function getAvatarText(): string {
94
-		$displayName = $this->getDisplayName();
95
-		if (empty($displayName) === true) {
96
-			return '?';
97
-		}
98
-		$firstTwoLetters = array_map(function ($namePart) {
99
-			return mb_strtoupper(mb_substr($namePart, 0, 1), 'UTF-8');
100
-		}, explode(' ', $displayName, 2));
101
-		return implode('', $firstTwoLetters);
102
-	}
103
-
104
-	/**
105
-	 * @inheritdoc
106
-	 */
107
-	public function get($size = 64) {
108
-		$size = (int) $size;
109
-
110
-		try {
111
-			$file = $this->getFile($size);
112
-		} catch (NotFoundException $e) {
113
-			return false;
114
-		}
115
-
116
-		$avatar = new OC_Image();
117
-		$avatar->loadFromData($file->getContent());
118
-		return $avatar;
119
-	}
120
-
121
-	/**
122
-	 * {size} = 500
123
-	 * {fill} = hex color to fill
124
-	 * {letter} = Letter to display
125
-	 *
126
-	 * Generate SVG avatar
127
-	 *
128
-	 * @param int $size The requested image size in pixel
129
-	 * @return string
130
-	 *
131
-	 */
132
-	protected function getAvatarVector(int $size): string {
133
-		$userDisplayName = $this->getDisplayName();
134
-		$bgRGB = $this->avatarBackgroundColor($userDisplayName);
135
-		$bgHEX = sprintf("%02x%02x%02x", $bgRGB->r, $bgRGB->g, $bgRGB->b);
136
-		$text = $this->getAvatarText();
137
-		$toReplace = ['{size}', '{fill}', '{letter}'];
138
-		return str_replace($toReplace, [$size, $bgHEX, $text], $this->svgTemplate);
139
-	}
140
-
141
-	/**
142
-	 * Generate png avatar from svg with Imagick
143
-	 *
144
-	 * @param int $size
145
-	 * @return string|boolean
146
-	 */
147
-	protected function generateAvatarFromSvg(int $size) {
148
-		if (!extension_loaded('imagick')) {
149
-			return false;
150
-		}
151
-		try {
152
-			$font = __DIR__ . '/../../core/fonts/NotoSans-Regular.ttf';
153
-			$svg = $this->getAvatarVector($size);
154
-			$avatar = new Imagick();
155
-			$avatar->setFont($font);
156
-			$avatar->readImageBlob($svg);
157
-			$avatar->setImageFormat('png');
158
-			$image = new OC_Image();
159
-			$image->loadFromData((string)$avatar);
160
-			$data = $image->data();
161
-			return $data === null ? false : $data;
162
-		} catch (\Exception $e) {
163
-			return false;
164
-		}
165
-	}
166
-
167
-	/**
168
-	 * Generate png avatar with GD
169
-	 *
170
-	 * @param string $userDisplayName
171
-	 * @param int $size
172
-	 * @return string
173
-	 */
174
-	protected function generateAvatar($userDisplayName, $size) {
175
-		$text = $this->getAvatarText();
176
-		$backgroundColor = $this->avatarBackgroundColor($userDisplayName);
177
-
178
-		$im = imagecreatetruecolor($size, $size);
179
-		$background = imagecolorallocate(
180
-			$im,
181
-			$backgroundColor->r,
182
-			$backgroundColor->g,
183
-			$backgroundColor->b
184
-		);
185
-		$white = imagecolorallocate($im, 255, 255, 255);
186
-		imagefilledrectangle($im, 0, 0, $size, $size, $background);
187
-
188
-		$font = __DIR__ . '/../../../core/fonts/NotoSans-Regular.ttf';
189
-
190
-		$fontSize = $size * 0.4;
191
-		[$x, $y] = $this->imageTTFCenter(
192
-			$im, $text, $font, (int)$fontSize
193
-		);
194
-
195
-		imagettftext($im, $fontSize, 0, $x, $y, $white, $font, $text);
196
-
197
-		ob_start();
198
-		imagepng($im);
199
-		$data = ob_get_contents();
200
-		ob_end_clean();
201
-
202
-		return $data;
203
-	}
204
-
205
-	/**
206
-	 * Calculate real image ttf center
207
-	 *
208
-	 * @param resource $image
209
-	 * @param string $text text string
210
-	 * @param string $font font path
211
-	 * @param int $size font size
212
-	 * @param int $angle
213
-	 * @return array
214
-	 */
215
-	protected function imageTTFCenter(
216
-		$image,
217
-		string $text,
218
-		string $font,
219
-		int $size,
220
-		$angle = 0
221
-	): array {
222
-		// Image width & height
223
-		$xi = imagesx($image);
224
-		$yi = imagesy($image);
225
-
226
-		// bounding box
227
-		$box = imagettfbbox($size, $angle, $font, $text);
228
-
229
-		// imagettfbbox can return negative int
230
-		$xr = abs(max($box[2], $box[4]));
231
-		$yr = abs(max($box[5], $box[7]));
232
-
233
-		// calculate bottom left placement
234
-		$x = intval(($xi - $xr) / 2);
235
-		$y = intval(($yi + $yr) / 2);
236
-
237
-		return [$x, $y];
238
-	}
239
-
240
-	/**
241
-	 * Calculate steps between two Colors
242
-	 * @param object Color $steps start color
243
-	 * @param object Color $ends end color
244
-	 * @return array [r,g,b] steps for each color to go from $steps to $ends
245
-	 */
246
-	private function stepCalc($steps, $ends) {
247
-		$step = [];
248
-		$step[0] = ($ends[1]->r - $ends[0]->r) / $steps;
249
-		$step[1] = ($ends[1]->g - $ends[0]->g) / $steps;
250
-		$step[2] = ($ends[1]->b - $ends[0]->b) / $steps;
251
-		return $step;
252
-	}
253
-
254
-	/**
255
-	 * Convert a string to an integer evenly
256
-	 * @param string $hash the text to parse
257
-	 * @param int $maximum the maximum range
258
-	 * @return int[] between 0 and $maximum
259
-	 */
260
-	private function mixPalette($steps, $color1, $color2) {
261
-		$palette = [$color1];
262
-		$step = $this->stepCalc($steps, [$color1, $color2]);
263
-		for ($i = 1; $i < $steps; $i++) {
264
-			$r = intval($color1->r + ($step[0] * $i));
265
-			$g = intval($color1->g + ($step[1] * $i));
266
-			$b = intval($color1->b + ($step[2] * $i));
267
-			$palette[] = new Color($r, $g, $b);
268
-		}
269
-		return $palette;
270
-	}
271
-
272
-	/**
273
-	 * Convert a string to an integer evenly
274
-	 * @param string $hash the text to parse
275
-	 * @param int $maximum the maximum range
276
-	 * @return int between 0 and $maximum
277
-	 */
278
-	private function hashToInt($hash, $maximum) {
279
-		$final = 0;
280
-		$result = [];
281
-
282
-		// Splitting evenly the string
283
-		for ($i = 0; $i < strlen($hash); $i++) {
284
-			// chars in md5 goes up to f, hex:16
285
-			$result[] = intval(substr($hash, $i, 1), 16) % 16;
286
-		}
287
-		// Adds up all results
288
-		foreach ($result as $value) {
289
-			$final += $value;
290
-		}
291
-		// chars in md5 goes up to f, hex:16
292
-		return intval($final % $maximum);
293
-	}
294
-
295
-	/**
296
-	 * @param string $hash
297
-	 * @return Color Object containting r g b int in the range [0, 255]
298
-	 */
299
-	public function avatarBackgroundColor(string $hash) {
300
-		// Normalize hash
301
-		$hash = strtolower($hash);
302
-
303
-		// Already a md5 hash?
304
-		if (preg_match('/^([0-9a-f]{4}-?){8}$/', $hash, $matches) !== 1) {
305
-			$hash = md5($hash);
306
-		}
307
-
308
-		// Remove unwanted char
309
-		$hash = preg_replace('/[^0-9a-f]+/', '', $hash);
310
-
311
-		$red = new Color(182, 70, 157);
312
-		$yellow = new Color(221, 203, 85);
313
-		$blue = new Color(0, 130, 201); // Nextcloud blue
314
-
315
-		// Number of steps to go from a color to another
316
-		// 3 colors * 6 will result in 18 generated colors
317
-		$steps = 6;
318
-
319
-		$palette1 = $this->mixPalette($steps, $red, $yellow);
320
-		$palette2 = $this->mixPalette($steps, $yellow, $blue);
321
-		$palette3 = $this->mixPalette($steps, $blue, $red);
322
-
323
-		$finalPalette = array_merge($palette1, $palette2, $palette3);
324
-
325
-		return $finalPalette[$this->hashToInt($hash, $steps * 3)];
326
-	}
72
+    /**
73
+     * The base avatar constructor.
74
+     *
75
+     * @param ILogger $logger The logger
76
+     */
77
+    public function __construct(ILogger $logger) {
78
+        $this->logger = $logger;
79
+    }
80
+
81
+    /**
82
+     * Returns the user display name.
83
+     *
84
+     * @return string
85
+     */
86
+    abstract public function getDisplayName(): string;
87
+
88
+    /**
89
+     * Returns the first letter of the display name, or "?" if no name given.
90
+     *
91
+     * @return string
92
+     */
93
+    private function getAvatarText(): string {
94
+        $displayName = $this->getDisplayName();
95
+        if (empty($displayName) === true) {
96
+            return '?';
97
+        }
98
+        $firstTwoLetters = array_map(function ($namePart) {
99
+            return mb_strtoupper(mb_substr($namePart, 0, 1), 'UTF-8');
100
+        }, explode(' ', $displayName, 2));
101
+        return implode('', $firstTwoLetters);
102
+    }
103
+
104
+    /**
105
+     * @inheritdoc
106
+     */
107
+    public function get($size = 64) {
108
+        $size = (int) $size;
109
+
110
+        try {
111
+            $file = $this->getFile($size);
112
+        } catch (NotFoundException $e) {
113
+            return false;
114
+        }
115
+
116
+        $avatar = new OC_Image();
117
+        $avatar->loadFromData($file->getContent());
118
+        return $avatar;
119
+    }
120
+
121
+    /**
122
+     * {size} = 500
123
+     * {fill} = hex color to fill
124
+     * {letter} = Letter to display
125
+     *
126
+     * Generate SVG avatar
127
+     *
128
+     * @param int $size The requested image size in pixel
129
+     * @return string
130
+     *
131
+     */
132
+    protected function getAvatarVector(int $size): string {
133
+        $userDisplayName = $this->getDisplayName();
134
+        $bgRGB = $this->avatarBackgroundColor($userDisplayName);
135
+        $bgHEX = sprintf("%02x%02x%02x", $bgRGB->r, $bgRGB->g, $bgRGB->b);
136
+        $text = $this->getAvatarText();
137
+        $toReplace = ['{size}', '{fill}', '{letter}'];
138
+        return str_replace($toReplace, [$size, $bgHEX, $text], $this->svgTemplate);
139
+    }
140
+
141
+    /**
142
+     * Generate png avatar from svg with Imagick
143
+     *
144
+     * @param int $size
145
+     * @return string|boolean
146
+     */
147
+    protected function generateAvatarFromSvg(int $size) {
148
+        if (!extension_loaded('imagick')) {
149
+            return false;
150
+        }
151
+        try {
152
+            $font = __DIR__ . '/../../core/fonts/NotoSans-Regular.ttf';
153
+            $svg = $this->getAvatarVector($size);
154
+            $avatar = new Imagick();
155
+            $avatar->setFont($font);
156
+            $avatar->readImageBlob($svg);
157
+            $avatar->setImageFormat('png');
158
+            $image = new OC_Image();
159
+            $image->loadFromData((string)$avatar);
160
+            $data = $image->data();
161
+            return $data === null ? false : $data;
162
+        } catch (\Exception $e) {
163
+            return false;
164
+        }
165
+    }
166
+
167
+    /**
168
+     * Generate png avatar with GD
169
+     *
170
+     * @param string $userDisplayName
171
+     * @param int $size
172
+     * @return string
173
+     */
174
+    protected function generateAvatar($userDisplayName, $size) {
175
+        $text = $this->getAvatarText();
176
+        $backgroundColor = $this->avatarBackgroundColor($userDisplayName);
177
+
178
+        $im = imagecreatetruecolor($size, $size);
179
+        $background = imagecolorallocate(
180
+            $im,
181
+            $backgroundColor->r,
182
+            $backgroundColor->g,
183
+            $backgroundColor->b
184
+        );
185
+        $white = imagecolorallocate($im, 255, 255, 255);
186
+        imagefilledrectangle($im, 0, 0, $size, $size, $background);
187
+
188
+        $font = __DIR__ . '/../../../core/fonts/NotoSans-Regular.ttf';
189
+
190
+        $fontSize = $size * 0.4;
191
+        [$x, $y] = $this->imageTTFCenter(
192
+            $im, $text, $font, (int)$fontSize
193
+        );
194
+
195
+        imagettftext($im, $fontSize, 0, $x, $y, $white, $font, $text);
196
+
197
+        ob_start();
198
+        imagepng($im);
199
+        $data = ob_get_contents();
200
+        ob_end_clean();
201
+
202
+        return $data;
203
+    }
204
+
205
+    /**
206
+     * Calculate real image ttf center
207
+     *
208
+     * @param resource $image
209
+     * @param string $text text string
210
+     * @param string $font font path
211
+     * @param int $size font size
212
+     * @param int $angle
213
+     * @return array
214
+     */
215
+    protected function imageTTFCenter(
216
+        $image,
217
+        string $text,
218
+        string $font,
219
+        int $size,
220
+        $angle = 0
221
+    ): array {
222
+        // Image width & height
223
+        $xi = imagesx($image);
224
+        $yi = imagesy($image);
225
+
226
+        // bounding box
227
+        $box = imagettfbbox($size, $angle, $font, $text);
228
+
229
+        // imagettfbbox can return negative int
230
+        $xr = abs(max($box[2], $box[4]));
231
+        $yr = abs(max($box[5], $box[7]));
232
+
233
+        // calculate bottom left placement
234
+        $x = intval(($xi - $xr) / 2);
235
+        $y = intval(($yi + $yr) / 2);
236
+
237
+        return [$x, $y];
238
+    }
239
+
240
+    /**
241
+     * Calculate steps between two Colors
242
+     * @param object Color $steps start color
243
+     * @param object Color $ends end color
244
+     * @return array [r,g,b] steps for each color to go from $steps to $ends
245
+     */
246
+    private function stepCalc($steps, $ends) {
247
+        $step = [];
248
+        $step[0] = ($ends[1]->r - $ends[0]->r) / $steps;
249
+        $step[1] = ($ends[1]->g - $ends[0]->g) / $steps;
250
+        $step[2] = ($ends[1]->b - $ends[0]->b) / $steps;
251
+        return $step;
252
+    }
253
+
254
+    /**
255
+     * Convert a string to an integer evenly
256
+     * @param string $hash the text to parse
257
+     * @param int $maximum the maximum range
258
+     * @return int[] between 0 and $maximum
259
+     */
260
+    private function mixPalette($steps, $color1, $color2) {
261
+        $palette = [$color1];
262
+        $step = $this->stepCalc($steps, [$color1, $color2]);
263
+        for ($i = 1; $i < $steps; $i++) {
264
+            $r = intval($color1->r + ($step[0] * $i));
265
+            $g = intval($color1->g + ($step[1] * $i));
266
+            $b = intval($color1->b + ($step[2] * $i));
267
+            $palette[] = new Color($r, $g, $b);
268
+        }
269
+        return $palette;
270
+    }
271
+
272
+    /**
273
+     * Convert a string to an integer evenly
274
+     * @param string $hash the text to parse
275
+     * @param int $maximum the maximum range
276
+     * @return int between 0 and $maximum
277
+     */
278
+    private function hashToInt($hash, $maximum) {
279
+        $final = 0;
280
+        $result = [];
281
+
282
+        // Splitting evenly the string
283
+        for ($i = 0; $i < strlen($hash); $i++) {
284
+            // chars in md5 goes up to f, hex:16
285
+            $result[] = intval(substr($hash, $i, 1), 16) % 16;
286
+        }
287
+        // Adds up all results
288
+        foreach ($result as $value) {
289
+            $final += $value;
290
+        }
291
+        // chars in md5 goes up to f, hex:16
292
+        return intval($final % $maximum);
293
+    }
294
+
295
+    /**
296
+     * @param string $hash
297
+     * @return Color Object containting r g b int in the range [0, 255]
298
+     */
299
+    public function avatarBackgroundColor(string $hash) {
300
+        // Normalize hash
301
+        $hash = strtolower($hash);
302
+
303
+        // Already a md5 hash?
304
+        if (preg_match('/^([0-9a-f]{4}-?){8}$/', $hash, $matches) !== 1) {
305
+            $hash = md5($hash);
306
+        }
307
+
308
+        // Remove unwanted char
309
+        $hash = preg_replace('/[^0-9a-f]+/', '', $hash);
310
+
311
+        $red = new Color(182, 70, 157);
312
+        $yellow = new Color(221, 203, 85);
313
+        $blue = new Color(0, 130, 201); // Nextcloud blue
314
+
315
+        // Number of steps to go from a color to another
316
+        // 3 colors * 6 will result in 18 generated colors
317
+        $steps = 6;
318
+
319
+        $palette1 = $this->mixPalette($steps, $red, $yellow);
320
+        $palette2 = $this->mixPalette($steps, $yellow, $blue);
321
+        $palette3 = $this->mixPalette($steps, $blue, $red);
322
+
323
+        $finalPalette = array_merge($palette1, $palette2, $palette3);
324
+
325
+        return $finalPalette[$this->hashToInt($hash, $steps * 3)];
326
+    }
327 327
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -95,7 +95,7 @@  discard block
 block discarded – undo
95 95
 		if (empty($displayName) === true) {
96 96
 			return '?';
97 97
 		}
98
-		$firstTwoLetters = array_map(function ($namePart) {
98
+		$firstTwoLetters = array_map(function($namePart) {
99 99
 			return mb_strtoupper(mb_substr($namePart, 0, 1), 'UTF-8');
100 100
 		}, explode(' ', $displayName, 2));
101 101
 		return implode('', $firstTwoLetters);
@@ -149,14 +149,14 @@  discard block
 block discarded – undo
149 149
 			return false;
150 150
 		}
151 151
 		try {
152
-			$font = __DIR__ . '/../../core/fonts/NotoSans-Regular.ttf';
152
+			$font = __DIR__.'/../../core/fonts/NotoSans-Regular.ttf';
153 153
 			$svg = $this->getAvatarVector($size);
154 154
 			$avatar = new Imagick();
155 155
 			$avatar->setFont($font);
156 156
 			$avatar->readImageBlob($svg);
157 157
 			$avatar->setImageFormat('png');
158 158
 			$image = new OC_Image();
159
-			$image->loadFromData((string)$avatar);
159
+			$image->loadFromData((string) $avatar);
160 160
 			$data = $image->data();
161 161
 			return $data === null ? false : $data;
162 162
 		} catch (\Exception $e) {
@@ -185,11 +185,11 @@  discard block
 block discarded – undo
185 185
 		$white = imagecolorallocate($im, 255, 255, 255);
186 186
 		imagefilledrectangle($im, 0, 0, $size, $size, $background);
187 187
 
188
-		$font = __DIR__ . '/../../../core/fonts/NotoSans-Regular.ttf';
188
+		$font = __DIR__.'/../../../core/fonts/NotoSans-Regular.ttf';
189 189
 
190 190
 		$fontSize = $size * 0.4;
191 191
 		[$x, $y] = $this->imageTTFCenter(
192
-			$im, $text, $font, (int)$fontSize
192
+			$im, $text, $font, (int) $fontSize
193 193
 		);
194 194
 
195 195
 		imagettftext($im, $fontSize, 0, $x, $y, $white, $font, $text);
Please login to merge, or discard this patch.