@@ -37,7 +37,7 @@ public function getBorder() {
37
37
public function getBuiltinFileKey () {
38
38
$ icon = $ this ->getIcon ();
39
39
$ color = $ this ->getColor ();
40
- $ border = $ this ->getBorder ();
40
+ $ border = implode ( ' , ' , $ this ->getBorder () );
41
41
$ desc = "compose(icon= {$ icon }, color= {$ color }, border= {$ border }" ;
42
42
$ hash = PhabricatorHash::digestToLength ($ desc , 40 );
43
43
return "builtin: {$ hash }" ;
@@ -46,7 +46,7 @@ public function getBuiltinFileKey() {
46
46
public function getBuiltinDisplayName () {
47
47
$ icon = $ this ->getIcon ();
48
48
$ color = $ this ->getColor ();
49
- $ border = $ this ->getBorder ();
49
+ $ border = implode ( ' , ' , $ this ->getBorder () );
50
50
return "{$ icon }- {$ color }- {$ border }.png " ;
51
51
}
52
52
@@ -55,30 +55,160 @@ public function loadBuiltinFileData() {
55
55
$ this ->getColor (), $ this ->getIcon (), $ this ->getBorder ());
56
56
}
57
57
58
- private function composeImage ($ color , $ icon , $ border ) {
59
- // TODO
58
+ private function composeImage ($ color , $ image , $ border ) {
59
+ $ color_const = hexdec (trim ($ color , '# ' ));
60
+ $ true_border = self ::rgba2gd ($ border );
61
+ $ image_map = self ::getImageMap ();
62
+ $ data = Filesystem::readFile ($ image_map [$ image ]);
63
+
64
+ $ img = imagecreatefromstring ($ data );
65
+
66
+ // 4 pixel border at 50x50, 32 pixel border at 400x400
67
+ $ canvas = imagecreatetruecolor (400 , 400 );
68
+
69
+ $ image_fill = imagefill ($ canvas , 0 , 0 , $ color_const );
70
+ if (!$ image_fill ) {
71
+ throw new Exception (
72
+ pht ('Failed to save builtin avatar image data (imagefill). ' ));
73
+ }
74
+
75
+ $ border_thickness = imagesetthickness ($ canvas , 64 );
76
+ if (!$ border_thickness ) {
77
+ throw new Exception (
78
+ pht ('Failed to save builtin avatar image data (imagesetthickness). ' ));
79
+ }
80
+
81
+ $ image_rectangle = imagerectangle ($ canvas , 0 , 0 , 400 , 400 , $ true_border );
82
+ if (!$ image_rectangle ) {
83
+ throw new Exception (
84
+ pht ('Failed to save builtin avatar image data (imagerectangle). ' ));
85
+ }
86
+
87
+ $ image_copy = imagecopy ($ canvas , $ img , 0 , 0 , 0 , 0 , 400 , 400 );
88
+ if (!$ image_copy ) {
89
+ throw new Exception (
90
+ pht ('Failed to save builtin avatar image data (imagecopy). ' ));
91
+ }
92
+
93
+ return PhabricatorImageTransformer::saveImageDataInAnyFormat (
94
+ $ canvas ,
95
+ 'image/png ' );
96
+ }
97
+
98
+ private static function rgba2gd ($ rgba ) {
99
+ $ r = $ rgba [0 ];
100
+ $ g = $ rgba [1 ];
101
+ $ b = $ rgba [2 ];
102
+ $ a = $ rgba [3 ];
103
+ $ a = (1 - $ a ) * 255 ;
104
+ return ($ a << 24 ) | ($ r << 16 ) | ($ g << 8 ) | $ b ;
60
105
}
61
106
62
107
public static function getImageMap () {
63
108
$ root = dirname (phutil_get_library_root ('phabricator ' ));
64
109
$ root = $ root .'/resources/builtin/alphanumeric/ ' ;
65
110
66
111
$ map = array ();
67
- $ list = Filesystem::listDirectory ($ root , $ include_hidden = false );
112
+ $ list = id (new FileFinder ($ root ))
113
+ ->withType ('f ' )
114
+ ->withFollowSymlinks (true )
115
+ ->find ();
116
+
68
117
foreach ($ list as $ file ) {
69
- $ key = 'alphanumeric/ ' .$ file ;
70
- $ map [$ key ] = $ root .$ file ;
118
+ $ map ['alphanumeric/ ' .$ file ] = $ root .$ file ;
119
+ }
120
+ return $ map ;
121
+ }
122
+
123
+ public function getUniqueProfileImage ($ username ) {
124
+ $ pack_map = $ this ->getImagePackMap ();
125
+ $ image_map = $ this ->getImageMap ();
126
+ $ color_map = $ this ->getColorMap ();
127
+ $ border_map = $ this ->getBorderMap ();
128
+ $ file = phutil_utf8_strtoupper (substr ($ username , 0 , 1 ));
129
+
130
+ $ pack_count = count ($ pack_map );
131
+ $ color_count = count ($ color_map );
132
+ $ border_count = count ($ border_map );
133
+
134
+ $ pack_seed = $ username .'_pack ' ;
135
+ $ color_seed = $ username .'_color ' ;
136
+ $ border_seed = $ username .'_border ' ;
137
+
138
+ $ pack_key =
139
+ PhabricatorHash::digestToRange ($ pack_seed , 1 , $ pack_count );
140
+ $ color_key =
141
+ PhabricatorHash::digestToRange ($ color_seed , 1 , $ color_count );
142
+ $ border_key =
143
+ PhabricatorHash::digestToRange ($ border_seed , 1 , $ border_count );
144
+
145
+ $ pack = $ pack_map [$ pack_key ];
146
+ $ icon = 'alphanumeric/ ' .$ pack .'/ ' .$ file .'.png ' ;
147
+ $ color = $ color_map [$ color_key ];
148
+ $ border = $ border_map [$ border_key ];
149
+
150
+ if (!isset ($ image_map [$ icon ])) {
151
+ $ icon = 'alphanumeric/ ' .$ pack .'/_default.png ' ;
71
152
}
72
153
154
+ return array ('color ' => $ color , 'icon ' => $ icon , 'border ' => $ border );
155
+ }
156
+
157
+ public function getUserProfileImageFile ($ username ) {
158
+ $ unique = $ this ->getUniqueProfileImage ($ username );
159
+
160
+ $ composer = id (new self ())
161
+ ->setIcon ($ unique ['icon ' ])
162
+ ->setColor ($ unique ['color ' ])
163
+ ->setBorder ($ unique ['border ' ]);
164
+
165
+ $ data = $ composer ->loadBuiltinFileData ();
166
+
167
+ $ unguarded = AphrontWriteGuard::beginScopedUnguardedWrites ();
168
+ $ file = PhabricatorFile::newFromFileData (
169
+ $ data ,
170
+ array (
171
+ 'name ' => $ composer ->getBuiltinDisplayName (),
172
+ 'profile ' => true ,
173
+ 'canCDN ' => true ,
174
+ ));
175
+ unset($ unguarded );
176
+
177
+ return $ file ;
178
+ }
179
+
180
+ public static function getImagePackMap () {
181
+ $ root = dirname (phutil_get_library_root ('phabricator ' ));
182
+ $ root = $ root .'/resources/builtin/alphanumeric/ ' ;
183
+
184
+ $ map = id (new FileFinder ($ root ))
185
+ ->withType ('d ' )
186
+ ->withFollowSymlinks (false )
187
+ ->find ();
188
+
189
+ return $ map ;
190
+ }
191
+
192
+ public static function getBorderMap () {
193
+
194
+ $ map = array (
195
+ array (0 , 0 , 0 , 0 ),
196
+ array (0 , 0 , 0 , 0.3 ),
197
+ array (255 , 255 , 255 , 0.4 ),
198
+ array (255 , 255 , 255 , 0.7 ),
199
+ );
200
+
73
201
return $ map ;
74
202
}
75
203
76
204
public static function getColorMap () {
205
+ //
206
+ // Generated Colors
207
+ // http://tools.medialab.sciences-po.fr/iwanthue/
208
+ //
77
209
$ map = array (
78
210
'#335862 ' ,
79
- '#dfc47b ' ,
80
211
'#2d5192 ' ,
81
- '#c0bc6e ' ,
82
212
'#3c5da0 ' ,
83
213
'#99cd86 ' ,
84
214
'#704889 ' ,
@@ -91,19 +221,14 @@ public static function getColorMap() {
91
221
'#4bd0e3 ' ,
92
222
'#a25542 ' ,
93
223
'#4eb4f3 ' ,
94
- '#705412 ' ,
95
224
'#6da8ec ' ,
96
225
'#545608 ' ,
97
226
'#829ce5 ' ,
98
227
'#68681d ' ,
99
228
'#607bc2 ' ,
100
- '#d1b66e ' ,
101
229
'#4b69ad ' ,
102
- '#a4a154 ' ,
103
230
'#236ead ' ,
104
- '#daa969 ' ,
105
231
'#31a0de ' ,
106
- '#996f31 ' ,
107
232
'#4f8ed0 ' ,
108
233
'#846f2a ' ,
109
234
'#bdb0f0 ' ,
@@ -121,13 +246,11 @@ public static function getColorMap() {
121
246
'#7f4c7f ' ,
122
247
'#a1bb7a ' ,
123
248
'#65558f ' ,
124
- '#c2a962 ' ,
125
249
'#445082 ' ,
126
250
'#c9ca8e ' ,
127
251
'#265582 ' ,
128
252
'#f4b189 ' ,
129
253
'#265582 ' ,
130
- '#bd8f50 ' ,
131
254
'#40b8e1 ' ,
132
255
'#814a28 ' ,
133
256
'#80c8f6 ' ,
@@ -142,7 +265,6 @@ public static function getColorMap() {
142
265
'#b888c9 ' ,
143
266
'#476025 ' ,
144
267
'#9987c5 ' ,
145
- '#828136 ' ,
146
268
'#7867a3 ' ,
147
269
'#769b5a ' ,
148
270
'#c46e9d ' ,
@@ -161,7 +283,6 @@ public static function getColorMap() {
161
283
'#45a998 ' ,
162
284
'#faa38c ' ,
163
285
'#265582 ' ,
164
- '#ad954f ' ,
165
286
'#265582 ' ,
166
287
'#e4b788 ' ,
167
288
'#265582 ' ,
@@ -187,7 +308,6 @@ public static function getColorMap() {
187
308
'#ae78ad ' ,
188
309
'#569160 ' ,
189
310
'#d898be ' ,
190
- '#525620 ' ,
191
311
'#8eb4e8 ' ,
192
312
'#5e622c ' ,
193
313
'#929ad3 ' ,
@@ -209,13 +329,9 @@ public static function getColorMap() {
209
329
'#63acda ' ,
210
330
'#7b5d30 ' ,
211
331
'#66bed6 ' ,
212
- '#a66c4e ' ,
213
332
'#3585b0 ' ,
214
- '#ba865c ' ,
215
333
'#5880b0 ' ,
216
- '#9b864d ' ,
217
334
'#739acc ' ,
218
- '#9d764a ' ,
219
335
'#48a3ba ' ,
220
336
'#9d565b ' ,
221
337
'#7fc4ca ' ,
@@ -232,15 +348,11 @@ public static function getColorMap() {
232
348
'#6bafb6 ' ,
233
349
'#8c5744 ' ,
234
350
'#84b9d6 ' ,
235
- '#725238 ' ,
236
351
'#9db3d6 ' ,
237
- '#816f3e ' ,
238
352
'#777cad ' ,
239
- '#a6a86e ' ,
240
353
'#826693 ' ,
241
354
'#86a779 ' ,
242
355
'#9d7fad ' ,
243
- '#8b8e55 ' ,
244
356
'#b193c2 ' ,
245
357
'#547348 ' ,
246
358
'#d5adcb ' ,
@@ -250,11 +362,9 @@ public static function getColorMap() {
250
362
'#b2add6 ' ,
251
363
'#5a623d ' ,
252
364
'#9793bb ' ,
253
- '#bea975 ' ,
254
365
'#3c5472 ' ,
255
366
'#d5c5a1 ' ,
256
367
'#5e5a7f ' ,
257
- '#b09c68 ' ,
258
368
'#2c647e ' ,
259
369
'#d8b194 ' ,
260
370
'#49607f ' ,
@@ -269,7 +379,6 @@ public static function getColorMap() {
269
379
'#ad697e ' ,
270
380
'#799a6d ' ,
271
381
'#916b88 ' ,
272
- '#aeb68d ' ,
273
382
'#69536b ' ,
274
383
'#b4c4ad ' ,
275
384
'#845865 ' ,
@@ -291,20 +400,16 @@ public static function getColorMap() {
291
400
'#50959b ' ,
292
401
'#b27d7a ' ,
293
402
'#335862 ' ,
294
- '#b2a381 ' ,
295
403
'#335862 ' ,
296
404
'#bcadc4 ' ,
297
405
'#706343 ' ,
298
406
'#749ebc ' ,
299
407
'#8c6a50 ' ,
300
408
'#92b8c4 ' ,
301
- '#a07d62 ' ,
302
409
'#758cad ' ,
303
410
'#868e67 ' ,
304
411
'#335862 ' ,
305
- '#b6978c ' ,
306
412
'#335862 ' ,
307
- '#9e8f6e ' ,
308
413
'#335862 ' ,
309
414
'#ac7e8b ' ,
310
415
'#77a185 ' ,
@@ -314,7 +419,6 @@ public static function getColorMap() {
314
419
'#467a70 ' ,
315
420
'#9b7d73 ' ,
316
421
'#335862 ' ,
317
- '#8a7c5b ' ,
318
422
'#335862 ' ,
319
423
'#8c9c85 ' ,
320
424
'#335862 ' ,
@@ -335,12 +439,4 @@ public static function getColorMap() {
335
439
return $ map ;
336
440
}
337
441
338
- public static function getBorderMap () {
339
- $ map = array (
340
- 'rgba(0,0,0,.3); ' , // Darker
341
- 'rgba(255,255,255,.5); ' , // Lighter
342
- );
343
- return $ map ;
344
- }
345
-
346
442
}
0 commit comments