diff --git a/resources/builtin/alphanumeric/Cd.png b/resources/builtin/alphanumeric/Cd.png deleted file mode 100644 index 66068c358a..0000000000 Binary files a/resources/builtin/alphanumeric/Cd.png and /dev/null differ diff --git a/resources/builtin/alphanumeric/Dd.png b/resources/builtin/alphanumeric/Dd.png deleted file mode 100644 index 7ed520452e..0000000000 Binary files a/resources/builtin/alphanumeric/Dd.png and /dev/null differ diff --git a/resources/builtin/alphanumeric/Gd.png b/resources/builtin/alphanumeric/Gd.png deleted file mode 100644 index 447c3a96b1..0000000000 Binary files a/resources/builtin/alphanumeric/Gd.png and /dev/null differ diff --git a/resources/builtin/alphanumeric/I.png b/resources/builtin/alphanumeric/I.png deleted file mode 100644 index b1ffcaad87..0000000000 Binary files a/resources/builtin/alphanumeric/I.png and /dev/null differ diff --git a/resources/builtin/alphanumeric/Id.png b/resources/builtin/alphanumeric/Id.png deleted file mode 100644 index a8564c8341..0000000000 Binary files a/resources/builtin/alphanumeric/Id.png and /dev/null differ diff --git a/resources/builtin/alphanumeric/L.png b/resources/builtin/alphanumeric/L.png deleted file mode 100644 index 44685fc20c..0000000000 Binary files a/resources/builtin/alphanumeric/L.png and /dev/null differ diff --git a/resources/builtin/alphanumeric/M.png b/resources/builtin/alphanumeric/M.png deleted file mode 100644 index d06924af48..0000000000 Binary files a/resources/builtin/alphanumeric/M.png and /dev/null differ diff --git a/resources/builtin/alphanumeric/Md.png b/resources/builtin/alphanumeric/Md.png deleted file mode 100644 index 8a4bea48df..0000000000 Binary files a/resources/builtin/alphanumeric/Md.png and /dev/null differ diff --git a/resources/builtin/alphanumeric/R.png b/resources/builtin/alphanumeric/R.png deleted file mode 100644 index 1afe1261b0..0000000000 Binary files a/resources/builtin/alphanumeric/R.png and /dev/null differ diff --git a/resources/builtin/alphanumeric/Rd.png b/resources/builtin/alphanumeric/Rd.png deleted file mode 100644 index 3d5bc1e8b1..0000000000 Binary files a/resources/builtin/alphanumeric/Rd.png and /dev/null differ diff --git a/resources/builtin/alphanumeric/Shrug.png b/resources/builtin/alphanumeric/Shrug.png deleted file mode 100644 index 400d911be8..0000000000 Binary files a/resources/builtin/alphanumeric/Shrug.png and /dev/null differ diff --git a/resources/builtin/alphanumeric/Shrug2.png b/resources/builtin/alphanumeric/Shrug2.png deleted file mode 100644 index 2eb4132a5f..0000000000 Binary files a/resources/builtin/alphanumeric/Shrug2.png and /dev/null differ diff --git a/resources/builtin/alphanumeric/Ud.png b/resources/builtin/alphanumeric/Ud.png deleted file mode 100644 index 3d5e9e7b23..0000000000 Binary files a/resources/builtin/alphanumeric/Ud.png and /dev/null differ diff --git a/resources/builtin/alphanumeric/V.png b/resources/builtin/alphanumeric/V.png deleted file mode 100644 index 4af0bb374f..0000000000 Binary files a/resources/builtin/alphanumeric/V.png and /dev/null differ diff --git a/resources/builtin/alphanumeric/Vd.png b/resources/builtin/alphanumeric/Vd.png deleted file mode 100644 index 0db539e1ca..0000000000 Binary files a/resources/builtin/alphanumeric/Vd.png and /dev/null differ diff --git a/resources/builtin/alphanumeric/aleo-white/0.png b/resources/builtin/alphanumeric/aleo-white/0.png new file mode 100644 index 0000000000..6a54cfbe1c Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/0.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/1.png b/resources/builtin/alphanumeric/aleo-white/1.png new file mode 100644 index 0000000000..0002e20ec4 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/1.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/2.png b/resources/builtin/alphanumeric/aleo-white/2.png new file mode 100644 index 0000000000..f3f4c558cf Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/2.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/3.png b/resources/builtin/alphanumeric/aleo-white/3.png new file mode 100644 index 0000000000..c4f3d5b171 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/3.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/4.png b/resources/builtin/alphanumeric/aleo-white/4.png new file mode 100644 index 0000000000..ee847ed0af Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/4.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/5.png b/resources/builtin/alphanumeric/aleo-white/5.png new file mode 100644 index 0000000000..e1bf184d68 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/5.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/6.png b/resources/builtin/alphanumeric/aleo-white/6.png new file mode 100644 index 0000000000..b585755282 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/6.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/7.png b/resources/builtin/alphanumeric/aleo-white/7.png new file mode 100644 index 0000000000..0609917f72 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/7.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/8.png b/resources/builtin/alphanumeric/aleo-white/8.png new file mode 100644 index 0000000000..fe328e3aaa Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/8.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/9.png b/resources/builtin/alphanumeric/aleo-white/9.png new file mode 100644 index 0000000000..bb27dd9595 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/9.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/A.png b/resources/builtin/alphanumeric/aleo-white/A.png new file mode 100644 index 0000000000..d78b8b82ca Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/A.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/B.png b/resources/builtin/alphanumeric/aleo-white/B.png new file mode 100644 index 0000000000..5692da0896 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/B.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/C.png b/resources/builtin/alphanumeric/aleo-white/C.png new file mode 100644 index 0000000000..2667930e6f Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/C.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/D.png b/resources/builtin/alphanumeric/aleo-white/D.png new file mode 100644 index 0000000000..f75ad9a591 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/D.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/E.png b/resources/builtin/alphanumeric/aleo-white/E.png new file mode 100644 index 0000000000..413cb4690c Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/E.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/F.png b/resources/builtin/alphanumeric/aleo-white/F.png new file mode 100644 index 0000000000..64c4db4622 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/F.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/G.png b/resources/builtin/alphanumeric/aleo-white/G.png new file mode 100644 index 0000000000..46ba2212f3 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/G.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/H.png b/resources/builtin/alphanumeric/aleo-white/H.png new file mode 100644 index 0000000000..23b1f78cfb Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/H.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/I.png b/resources/builtin/alphanumeric/aleo-white/I.png new file mode 100644 index 0000000000..222feb88e6 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/I.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/J.png b/resources/builtin/alphanumeric/aleo-white/J.png new file mode 100644 index 0000000000..d3c81deb19 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/J.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/K.png b/resources/builtin/alphanumeric/aleo-white/K.png new file mode 100644 index 0000000000..05c527b5cb Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/K.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/L.png b/resources/builtin/alphanumeric/aleo-white/L.png new file mode 100644 index 0000000000..cc6af32ef9 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/L.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/M.png b/resources/builtin/alphanumeric/aleo-white/M.png new file mode 100644 index 0000000000..9422d110e2 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/M.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/N.png b/resources/builtin/alphanumeric/aleo-white/N.png new file mode 100644 index 0000000000..6efde37f25 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/N.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/O.png b/resources/builtin/alphanumeric/aleo-white/O.png new file mode 100644 index 0000000000..e7266a7d0f Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/O.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/P.png b/resources/builtin/alphanumeric/aleo-white/P.png new file mode 100644 index 0000000000..e94a48a4cc Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/P.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/Q.png b/resources/builtin/alphanumeric/aleo-white/Q.png new file mode 100644 index 0000000000..8217bfef59 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/Q.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/R.png b/resources/builtin/alphanumeric/aleo-white/R.png new file mode 100644 index 0000000000..3cf3892f3e Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/R.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/S.png b/resources/builtin/alphanumeric/aleo-white/S.png new file mode 100644 index 0000000000..4c08cf5982 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/S.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/T.png b/resources/builtin/alphanumeric/aleo-white/T.png new file mode 100644 index 0000000000..6484a2856f Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/T.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/U.png b/resources/builtin/alphanumeric/aleo-white/U.png new file mode 100644 index 0000000000..af3427b455 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/U.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/V.png b/resources/builtin/alphanumeric/aleo-white/V.png new file mode 100644 index 0000000000..948d35a674 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/V.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/W.png b/resources/builtin/alphanumeric/aleo-white/W.png new file mode 100644 index 0000000000..5db225e845 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/W.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/X.png b/resources/builtin/alphanumeric/aleo-white/X.png new file mode 100644 index 0000000000..aed5084b77 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/X.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/Y.png b/resources/builtin/alphanumeric/aleo-white/Y.png new file mode 100644 index 0000000000..80475739e4 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/Y.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/Z.png b/resources/builtin/alphanumeric/aleo-white/Z.png new file mode 100644 index 0000000000..f58fc9eb55 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/Z.png differ diff --git a/resources/builtin/alphanumeric/aleo-white/_default.png b/resources/builtin/alphanumeric/aleo-white/_default.png new file mode 100644 index 0000000000..167ab46b39 Binary files /dev/null and b/resources/builtin/alphanumeric/aleo-white/_default.png differ diff --git a/resources/builtin/alphanumeric/0d.png b/resources/builtin/alphanumeric/lato-dark/0.png similarity index 100% rename from resources/builtin/alphanumeric/0d.png rename to resources/builtin/alphanumeric/lato-dark/0.png diff --git a/resources/builtin/alphanumeric/1d.png b/resources/builtin/alphanumeric/lato-dark/1.png similarity index 100% rename from resources/builtin/alphanumeric/1d.png rename to resources/builtin/alphanumeric/lato-dark/1.png diff --git a/resources/builtin/alphanumeric/2d.png b/resources/builtin/alphanumeric/lato-dark/2.png similarity index 100% rename from resources/builtin/alphanumeric/2d.png rename to resources/builtin/alphanumeric/lato-dark/2.png diff --git a/resources/builtin/alphanumeric/3d.png b/resources/builtin/alphanumeric/lato-dark/3.png similarity index 100% rename from resources/builtin/alphanumeric/3d.png rename to resources/builtin/alphanumeric/lato-dark/3.png diff --git a/resources/builtin/alphanumeric/4d.png b/resources/builtin/alphanumeric/lato-dark/4.png similarity index 100% rename from resources/builtin/alphanumeric/4d.png rename to resources/builtin/alphanumeric/lato-dark/4.png diff --git a/resources/builtin/alphanumeric/5d.png b/resources/builtin/alphanumeric/lato-dark/5.png similarity index 100% rename from resources/builtin/alphanumeric/5d.png rename to resources/builtin/alphanumeric/lato-dark/5.png diff --git a/resources/builtin/alphanumeric/6d.png b/resources/builtin/alphanumeric/lato-dark/6.png similarity index 100% rename from resources/builtin/alphanumeric/6d.png rename to resources/builtin/alphanumeric/lato-dark/6.png diff --git a/resources/builtin/alphanumeric/7d.png b/resources/builtin/alphanumeric/lato-dark/7.png similarity index 100% rename from resources/builtin/alphanumeric/7d.png rename to resources/builtin/alphanumeric/lato-dark/7.png diff --git a/resources/builtin/alphanumeric/8d.png b/resources/builtin/alphanumeric/lato-dark/8.png similarity index 100% rename from resources/builtin/alphanumeric/8d.png rename to resources/builtin/alphanumeric/lato-dark/8.png diff --git a/resources/builtin/alphanumeric/9d.png b/resources/builtin/alphanumeric/lato-dark/9.png similarity index 100% rename from resources/builtin/alphanumeric/9d.png rename to resources/builtin/alphanumeric/lato-dark/9.png diff --git a/resources/builtin/alphanumeric/Ad.png b/resources/builtin/alphanumeric/lato-dark/A.png similarity index 82% rename from resources/builtin/alphanumeric/Ad.png rename to resources/builtin/alphanumeric/lato-dark/A.png index 72c0102db9..96ec17c25a 100644 Binary files a/resources/builtin/alphanumeric/Ad.png and b/resources/builtin/alphanumeric/lato-dark/A.png differ diff --git a/resources/builtin/alphanumeric/Bd.png b/resources/builtin/alphanumeric/lato-dark/B.png similarity index 100% rename from resources/builtin/alphanumeric/Bd.png rename to resources/builtin/alphanumeric/lato-dark/B.png diff --git a/resources/builtin/alphanumeric/lato-dark/C.png b/resources/builtin/alphanumeric/lato-dark/C.png new file mode 100644 index 0000000000..69245cb33d Binary files /dev/null and b/resources/builtin/alphanumeric/lato-dark/C.png differ diff --git a/resources/builtin/alphanumeric/lato-dark/D.png b/resources/builtin/alphanumeric/lato-dark/D.png new file mode 100644 index 0000000000..b6a4db9da7 Binary files /dev/null and b/resources/builtin/alphanumeric/lato-dark/D.png differ diff --git a/resources/builtin/alphanumeric/Ed.png b/resources/builtin/alphanumeric/lato-dark/E.png similarity index 100% rename from resources/builtin/alphanumeric/Ed.png rename to resources/builtin/alphanumeric/lato-dark/E.png diff --git a/resources/builtin/alphanumeric/Fd.png b/resources/builtin/alphanumeric/lato-dark/F.png similarity index 100% rename from resources/builtin/alphanumeric/Fd.png rename to resources/builtin/alphanumeric/lato-dark/F.png diff --git a/resources/builtin/alphanumeric/lato-dark/G.png b/resources/builtin/alphanumeric/lato-dark/G.png new file mode 100644 index 0000000000..54fb8a4659 Binary files /dev/null and b/resources/builtin/alphanumeric/lato-dark/G.png differ diff --git a/resources/builtin/alphanumeric/Hd.png b/resources/builtin/alphanumeric/lato-dark/H.png similarity index 100% rename from resources/builtin/alphanumeric/Hd.png rename to resources/builtin/alphanumeric/lato-dark/H.png diff --git a/resources/builtin/alphanumeric/lato-dark/I.png b/resources/builtin/alphanumeric/lato-dark/I.png new file mode 100644 index 0000000000..4455baec89 Binary files /dev/null and b/resources/builtin/alphanumeric/lato-dark/I.png differ diff --git a/resources/builtin/alphanumeric/Jd.png b/resources/builtin/alphanumeric/lato-dark/J.png similarity index 100% rename from resources/builtin/alphanumeric/Jd.png rename to resources/builtin/alphanumeric/lato-dark/J.png diff --git a/resources/builtin/alphanumeric/Kd.png b/resources/builtin/alphanumeric/lato-dark/K.png similarity index 100% rename from resources/builtin/alphanumeric/Kd.png rename to resources/builtin/alphanumeric/lato-dark/K.png diff --git a/resources/builtin/alphanumeric/Ld.png b/resources/builtin/alphanumeric/lato-dark/L.png similarity index 100% copy from resources/builtin/alphanumeric/Ld.png copy to resources/builtin/alphanumeric/lato-dark/L.png diff --git a/resources/builtin/alphanumeric/lato-dark/M.png b/resources/builtin/alphanumeric/lato-dark/M.png new file mode 100644 index 0000000000..46e9347578 Binary files /dev/null and b/resources/builtin/alphanumeric/lato-dark/M.png differ diff --git a/resources/builtin/alphanumeric/N.png b/resources/builtin/alphanumeric/lato-dark/N.png similarity index 70% rename from resources/builtin/alphanumeric/N.png rename to resources/builtin/alphanumeric/lato-dark/N.png index 06286a8c3f..e8cffda355 100644 Binary files a/resources/builtin/alphanumeric/N.png and b/resources/builtin/alphanumeric/lato-dark/N.png differ diff --git a/resources/builtin/alphanumeric/Od.png b/resources/builtin/alphanumeric/lato-dark/O.png similarity index 100% rename from resources/builtin/alphanumeric/Od.png rename to resources/builtin/alphanumeric/lato-dark/O.png diff --git a/resources/builtin/alphanumeric/Pd.png b/resources/builtin/alphanumeric/lato-dark/P.png similarity index 100% rename from resources/builtin/alphanumeric/Pd.png rename to resources/builtin/alphanumeric/lato-dark/P.png diff --git a/resources/builtin/alphanumeric/Qd.png b/resources/builtin/alphanumeric/lato-dark/Q.png similarity index 100% rename from resources/builtin/alphanumeric/Qd.png rename to resources/builtin/alphanumeric/lato-dark/Q.png diff --git a/resources/builtin/alphanumeric/lato-dark/R.png b/resources/builtin/alphanumeric/lato-dark/R.png new file mode 100644 index 0000000000..7213cb4911 Binary files /dev/null and b/resources/builtin/alphanumeric/lato-dark/R.png differ diff --git a/resources/builtin/alphanumeric/Sd.png b/resources/builtin/alphanumeric/lato-dark/S.png similarity index 100% rename from resources/builtin/alphanumeric/Sd.png rename to resources/builtin/alphanumeric/lato-dark/S.png diff --git a/resources/builtin/alphanumeric/Td.png b/resources/builtin/alphanumeric/lato-dark/T.png similarity index 100% rename from resources/builtin/alphanumeric/Td.png rename to resources/builtin/alphanumeric/lato-dark/T.png diff --git a/resources/builtin/alphanumeric/lato-dark/U.png b/resources/builtin/alphanumeric/lato-dark/U.png new file mode 100644 index 0000000000..467c8a9139 Binary files /dev/null and b/resources/builtin/alphanumeric/lato-dark/U.png differ diff --git a/resources/builtin/alphanumeric/lato-dark/V.png b/resources/builtin/alphanumeric/lato-dark/V.png new file mode 100644 index 0000000000..47626ba4ee Binary files /dev/null and b/resources/builtin/alphanumeric/lato-dark/V.png differ diff --git a/resources/builtin/alphanumeric/Wd.png b/resources/builtin/alphanumeric/lato-dark/W.png similarity index 100% rename from resources/builtin/alphanumeric/Wd.png rename to resources/builtin/alphanumeric/lato-dark/W.png diff --git a/resources/builtin/alphanumeric/Xd.png b/resources/builtin/alphanumeric/lato-dark/X.png similarity index 100% rename from resources/builtin/alphanumeric/Xd.png rename to resources/builtin/alphanumeric/lato-dark/X.png diff --git a/resources/builtin/alphanumeric/Yd.png b/resources/builtin/alphanumeric/lato-dark/Y.png similarity index 100% rename from resources/builtin/alphanumeric/Yd.png rename to resources/builtin/alphanumeric/lato-dark/Y.png diff --git a/resources/builtin/alphanumeric/Zd.png b/resources/builtin/alphanumeric/lato-dark/Z.png similarity index 100% rename from resources/builtin/alphanumeric/Zd.png rename to resources/builtin/alphanumeric/lato-dark/Z.png diff --git a/resources/builtin/alphanumeric/lato-dark/_default.png b/resources/builtin/alphanumeric/lato-dark/_default.png new file mode 100644 index 0000000000..48be8a15eb Binary files /dev/null and b/resources/builtin/alphanumeric/lato-dark/_default.png differ diff --git a/resources/builtin/alphanumeric/0.png b/resources/builtin/alphanumeric/lato-white/0.png similarity index 94% rename from resources/builtin/alphanumeric/0.png rename to resources/builtin/alphanumeric/lato-white/0.png index 08ba53a95c..a37a1305e3 100644 Binary files a/resources/builtin/alphanumeric/0.png and b/resources/builtin/alphanumeric/lato-white/0.png differ diff --git a/resources/builtin/alphanumeric/1.png b/resources/builtin/alphanumeric/lato-white/1.png similarity index 89% rename from resources/builtin/alphanumeric/1.png rename to resources/builtin/alphanumeric/lato-white/1.png index f5d7dcf9b3..e1b330190c 100644 Binary files a/resources/builtin/alphanumeric/1.png and b/resources/builtin/alphanumeric/lato-white/1.png differ diff --git a/resources/builtin/alphanumeric/2.png b/resources/builtin/alphanumeric/lato-white/2.png similarity index 92% rename from resources/builtin/alphanumeric/2.png rename to resources/builtin/alphanumeric/lato-white/2.png index 84ab492820..af3294627c 100644 Binary files a/resources/builtin/alphanumeric/2.png and b/resources/builtin/alphanumeric/lato-white/2.png differ diff --git a/resources/builtin/alphanumeric/3.png b/resources/builtin/alphanumeric/lato-white/3.png similarity index 95% rename from resources/builtin/alphanumeric/3.png rename to resources/builtin/alphanumeric/lato-white/3.png index 24b7bc23d4..fe48e50396 100644 Binary files a/resources/builtin/alphanumeric/3.png and b/resources/builtin/alphanumeric/lato-white/3.png differ diff --git a/resources/builtin/alphanumeric/4.png b/resources/builtin/alphanumeric/lato-white/4.png similarity index 90% rename from resources/builtin/alphanumeric/4.png rename to resources/builtin/alphanumeric/lato-white/4.png index a76d5d53a5..bd208785ca 100644 Binary files a/resources/builtin/alphanumeric/4.png and b/resources/builtin/alphanumeric/lato-white/4.png differ diff --git a/resources/builtin/alphanumeric/5.png b/resources/builtin/alphanumeric/lato-white/5.png similarity index 91% rename from resources/builtin/alphanumeric/5.png rename to resources/builtin/alphanumeric/lato-white/5.png index 51b96c1bf9..d93fe585c1 100644 Binary files a/resources/builtin/alphanumeric/5.png and b/resources/builtin/alphanumeric/lato-white/5.png differ diff --git a/resources/builtin/alphanumeric/6.png b/resources/builtin/alphanumeric/lato-white/6.png similarity index 94% rename from resources/builtin/alphanumeric/6.png rename to resources/builtin/alphanumeric/lato-white/6.png index b12283a8f7..fc54fbe317 100644 Binary files a/resources/builtin/alphanumeric/6.png and b/resources/builtin/alphanumeric/lato-white/6.png differ diff --git a/resources/builtin/alphanumeric/7.png b/resources/builtin/alphanumeric/lato-white/7.png similarity index 91% rename from resources/builtin/alphanumeric/7.png rename to resources/builtin/alphanumeric/lato-white/7.png index 198c8ae830..d77949da2f 100644 Binary files a/resources/builtin/alphanumeric/7.png and b/resources/builtin/alphanumeric/lato-white/7.png differ diff --git a/resources/builtin/alphanumeric/8.png b/resources/builtin/alphanumeric/lato-white/8.png similarity index 93% rename from resources/builtin/alphanumeric/8.png rename to resources/builtin/alphanumeric/lato-white/8.png index 22413d368a..4664d06d81 100644 Binary files a/resources/builtin/alphanumeric/8.png and b/resources/builtin/alphanumeric/lato-white/8.png differ diff --git a/resources/builtin/alphanumeric/9.png b/resources/builtin/alphanumeric/lato-white/9.png similarity index 94% rename from resources/builtin/alphanumeric/9.png rename to resources/builtin/alphanumeric/lato-white/9.png index 94c8216648..66058e023d 100644 Binary files a/resources/builtin/alphanumeric/9.png and b/resources/builtin/alphanumeric/lato-white/9.png differ diff --git a/resources/builtin/alphanumeric/A.png b/resources/builtin/alphanumeric/lato-white/A.png similarity index 95% rename from resources/builtin/alphanumeric/A.png rename to resources/builtin/alphanumeric/lato-white/A.png index 319b396aef..284ce2a060 100644 Binary files a/resources/builtin/alphanumeric/A.png and b/resources/builtin/alphanumeric/lato-white/A.png differ diff --git a/resources/builtin/alphanumeric/B.png b/resources/builtin/alphanumeric/lato-white/B.png similarity index 94% rename from resources/builtin/alphanumeric/B.png rename to resources/builtin/alphanumeric/lato-white/B.png index e6750a8db5..3fa4722ab3 100644 Binary files a/resources/builtin/alphanumeric/B.png and b/resources/builtin/alphanumeric/lato-white/B.png differ diff --git a/resources/builtin/alphanumeric/C.png b/resources/builtin/alphanumeric/lato-white/C.png similarity index 94% rename from resources/builtin/alphanumeric/C.png rename to resources/builtin/alphanumeric/lato-white/C.png index db9b1b1694..ee08793966 100644 Binary files a/resources/builtin/alphanumeric/C.png and b/resources/builtin/alphanumeric/lato-white/C.png differ diff --git a/resources/builtin/alphanumeric/D.png b/resources/builtin/alphanumeric/lato-white/D.png similarity index 94% rename from resources/builtin/alphanumeric/D.png rename to resources/builtin/alphanumeric/lato-white/D.png index a716809913..e100162e2a 100644 Binary files a/resources/builtin/alphanumeric/D.png and b/resources/builtin/alphanumeric/lato-white/D.png differ diff --git a/resources/builtin/alphanumeric/E.png b/resources/builtin/alphanumeric/lato-white/E.png similarity index 56% rename from resources/builtin/alphanumeric/E.png rename to resources/builtin/alphanumeric/lato-white/E.png index 52347141a5..0e6a648608 100644 Binary files a/resources/builtin/alphanumeric/E.png and b/resources/builtin/alphanumeric/lato-white/E.png differ diff --git a/resources/builtin/alphanumeric/F.png b/resources/builtin/alphanumeric/lato-white/F.png similarity index 70% rename from resources/builtin/alphanumeric/F.png rename to resources/builtin/alphanumeric/lato-white/F.png index 148167e17a..c0f43e59b3 100644 Binary files a/resources/builtin/alphanumeric/F.png and b/resources/builtin/alphanumeric/lato-white/F.png differ diff --git a/resources/builtin/alphanumeric/G.png b/resources/builtin/alphanumeric/lato-white/G.png similarity index 92% rename from resources/builtin/alphanumeric/G.png rename to resources/builtin/alphanumeric/lato-white/G.png index 259733582c..4a15c197ba 100644 Binary files a/resources/builtin/alphanumeric/G.png and b/resources/builtin/alphanumeric/lato-white/G.png differ diff --git a/resources/builtin/alphanumeric/H.png b/resources/builtin/alphanumeric/lato-white/H.png similarity index 72% rename from resources/builtin/alphanumeric/H.png rename to resources/builtin/alphanumeric/lato-white/H.png index 4dd59a11e2..0c627420fc 100644 Binary files a/resources/builtin/alphanumeric/H.png and b/resources/builtin/alphanumeric/lato-white/H.png differ diff --git a/resources/builtin/alphanumeric/lato-white/I.png b/resources/builtin/alphanumeric/lato-white/I.png new file mode 100644 index 0000000000..dfe79d9b35 Binary files /dev/null and b/resources/builtin/alphanumeric/lato-white/I.png differ diff --git a/resources/builtin/alphanumeric/J.png b/resources/builtin/alphanumeric/lato-white/J.png similarity index 55% rename from resources/builtin/alphanumeric/J.png rename to resources/builtin/alphanumeric/lato-white/J.png index fb92c9c8f1..a7ade6ba34 100644 Binary files a/resources/builtin/alphanumeric/J.png and b/resources/builtin/alphanumeric/lato-white/J.png differ diff --git a/resources/builtin/alphanumeric/K.png b/resources/builtin/alphanumeric/lato-white/K.png similarity index 90% rename from resources/builtin/alphanumeric/K.png rename to resources/builtin/alphanumeric/lato-white/K.png index 847f995d2f..894f16abf9 100644 Binary files a/resources/builtin/alphanumeric/K.png and b/resources/builtin/alphanumeric/lato-white/K.png differ diff --git a/resources/builtin/alphanumeric/Ld.png b/resources/builtin/alphanumeric/lato-white/L.png similarity index 62% rename from resources/builtin/alphanumeric/Ld.png rename to resources/builtin/alphanumeric/lato-white/L.png index 35e0557294..61889a13cb 100644 Binary files a/resources/builtin/alphanumeric/Ld.png and b/resources/builtin/alphanumeric/lato-white/L.png differ diff --git a/resources/builtin/alphanumeric/lato-white/M.png b/resources/builtin/alphanumeric/lato-white/M.png new file mode 100644 index 0000000000..a54a3639dc Binary files /dev/null and b/resources/builtin/alphanumeric/lato-white/M.png differ diff --git a/resources/builtin/alphanumeric/Nd.png b/resources/builtin/alphanumeric/lato-white/N.png similarity index 70% rename from resources/builtin/alphanumeric/Nd.png rename to resources/builtin/alphanumeric/lato-white/N.png index 84487725b9..051ec3c09d 100644 Binary files a/resources/builtin/alphanumeric/Nd.png and b/resources/builtin/alphanumeric/lato-white/N.png differ diff --git a/resources/builtin/alphanumeric/O.png b/resources/builtin/alphanumeric/lato-white/O.png similarity index 93% rename from resources/builtin/alphanumeric/O.png rename to resources/builtin/alphanumeric/lato-white/O.png index 757903c5e4..574d940f4f 100644 Binary files a/resources/builtin/alphanumeric/O.png and b/resources/builtin/alphanumeric/lato-white/O.png differ diff --git a/resources/builtin/alphanumeric/P.png b/resources/builtin/alphanumeric/lato-white/P.png similarity index 87% rename from resources/builtin/alphanumeric/P.png rename to resources/builtin/alphanumeric/lato-white/P.png index effe6a5097..0c735d3a4c 100644 Binary files a/resources/builtin/alphanumeric/P.png and b/resources/builtin/alphanumeric/lato-white/P.png differ diff --git a/resources/builtin/alphanumeric/Q.png b/resources/builtin/alphanumeric/lato-white/Q.png similarity index 96% rename from resources/builtin/alphanumeric/Q.png rename to resources/builtin/alphanumeric/lato-white/Q.png index 6b55072e55..b09b9b9a03 100644 Binary files a/resources/builtin/alphanumeric/Q.png and b/resources/builtin/alphanumeric/lato-white/Q.png differ diff --git a/resources/builtin/alphanumeric/lato-white/R.png b/resources/builtin/alphanumeric/lato-white/R.png new file mode 100644 index 0000000000..89f0fa8f26 Binary files /dev/null and b/resources/builtin/alphanumeric/lato-white/R.png differ diff --git a/resources/builtin/alphanumeric/S.png b/resources/builtin/alphanumeric/lato-white/S.png similarity index 93% rename from resources/builtin/alphanumeric/S.png rename to resources/builtin/alphanumeric/lato-white/S.png index 2ceddf040b..8992f0f6a0 100644 Binary files a/resources/builtin/alphanumeric/S.png and b/resources/builtin/alphanumeric/lato-white/S.png differ diff --git a/resources/builtin/alphanumeric/T.png b/resources/builtin/alphanumeric/lato-white/T.png similarity index 74% rename from resources/builtin/alphanumeric/T.png rename to resources/builtin/alphanumeric/lato-white/T.png index d970924b6a..5c9393b0ae 100644 Binary files a/resources/builtin/alphanumeric/T.png and b/resources/builtin/alphanumeric/lato-white/T.png differ diff --git a/resources/builtin/alphanumeric/U.png b/resources/builtin/alphanumeric/lato-white/U.png similarity index 89% rename from resources/builtin/alphanumeric/U.png rename to resources/builtin/alphanumeric/lato-white/U.png index 5e078eecfa..e681eb61f4 100644 Binary files a/resources/builtin/alphanumeric/U.png and b/resources/builtin/alphanumeric/lato-white/U.png differ diff --git a/resources/builtin/alphanumeric/lato-white/V.png b/resources/builtin/alphanumeric/lato-white/V.png new file mode 100644 index 0000000000..c2ffde7044 Binary files /dev/null and b/resources/builtin/alphanumeric/lato-white/V.png differ diff --git a/resources/builtin/alphanumeric/W.png b/resources/builtin/alphanumeric/lato-white/W.png similarity index 95% rename from resources/builtin/alphanumeric/W.png rename to resources/builtin/alphanumeric/lato-white/W.png index cf24b50496..60b3c36088 100644 Binary files a/resources/builtin/alphanumeric/W.png and b/resources/builtin/alphanumeric/lato-white/W.png differ diff --git a/resources/builtin/alphanumeric/X.png b/resources/builtin/alphanumeric/lato-white/X.png similarity index 94% rename from resources/builtin/alphanumeric/X.png rename to resources/builtin/alphanumeric/lato-white/X.png index ce32aafa85..60c82d00eb 100644 Binary files a/resources/builtin/alphanumeric/X.png and b/resources/builtin/alphanumeric/lato-white/X.png differ diff --git a/resources/builtin/alphanumeric/Y.png b/resources/builtin/alphanumeric/lato-white/Y.png similarity index 92% rename from resources/builtin/alphanumeric/Y.png rename to resources/builtin/alphanumeric/lato-white/Y.png index 95ec8bc41a..1f6bf139a2 100644 Binary files a/resources/builtin/alphanumeric/Y.png and b/resources/builtin/alphanumeric/lato-white/Y.png differ diff --git a/resources/builtin/alphanumeric/Z.png b/resources/builtin/alphanumeric/lato-white/Z.png similarity index 87% rename from resources/builtin/alphanumeric/Z.png rename to resources/builtin/alphanumeric/lato-white/Z.png index e8892e264b..6f06c52cdc 100644 Binary files a/resources/builtin/alphanumeric/Z.png and b/resources/builtin/alphanumeric/lato-white/Z.png differ diff --git a/resources/builtin/alphanumeric/lato-white/_default.png b/resources/builtin/alphanumeric/lato-white/_default.png new file mode 100644 index 0000000000..e6be069919 Binary files /dev/null and b/resources/builtin/alphanumeric/lato-white/_default.png differ diff --git a/src/applications/files/builtin/PhabricatorFilesComposeAvatarBuiltinFile.php b/src/applications/files/builtin/PhabricatorFilesComposeAvatarBuiltinFile.php index 098254ffa6..29acacc188 100644 --- a/src/applications/files/builtin/PhabricatorFilesComposeAvatarBuiltinFile.php +++ b/src/applications/files/builtin/PhabricatorFilesComposeAvatarBuiltinFile.php @@ -1,346 +1,442 @@ icon = $icon; return $this; } public function getIcon() { return $this->icon; } public function setColor($color) { $this->color = $color; return $this; } public function getColor() { return $this->color; } public function setBorder($border) { $this->border = $border; return $this; } public function getBorder() { return $this->border; } public function getBuiltinFileKey() { $icon = $this->getIcon(); $color = $this->getColor(); - $border = $this->getBorder(); + $border = implode(',', $this->getBorder()); $desc = "compose(icon={$icon}, color={$color}, border={$border}"; $hash = PhabricatorHash::digestToLength($desc, 40); return "builtin:{$hash}"; } public function getBuiltinDisplayName() { $icon = $this->getIcon(); $color = $this->getColor(); - $border = $this->getBorder(); + $border = implode(',', $this->getBorder()); return "{$icon}-{$color}-{$border}.png"; } public function loadBuiltinFileData() { return $this->composeImage( $this->getColor(), $this->getIcon(), $this->getBorder()); } - private function composeImage($color, $icon, $border) { - // TODO + private function composeImage($color, $image, $border) { + $color_const = hexdec(trim($color, '#')); + $true_border = self::rgba2gd($border); + $image_map = self::getImageMap(); + $data = Filesystem::readFile($image_map[$image]); + + $img = imagecreatefromstring($data); + + // 4 pixel border at 50x50, 32 pixel border at 400x400 + $canvas = imagecreatetruecolor(400, 400); + + $image_fill = imagefill($canvas, 0, 0, $color_const); + if (!$image_fill) { + throw new Exception( + pht('Failed to save builtin avatar image data (imagefill).')); + } + + $border_thickness = imagesetthickness($canvas, 64); + if (!$border_thickness) { + throw new Exception( + pht('Failed to save builtin avatar image data (imagesetthickness).')); + } + + $image_rectangle = imagerectangle($canvas, 0, 0, 400, 400, $true_border); + if (!$image_rectangle) { + throw new Exception( + pht('Failed to save builtin avatar image data (imagerectangle).')); + } + + $image_copy = imagecopy($canvas, $img, 0, 0, 0, 0, 400, 400); + if (!$image_copy) { + throw new Exception( + pht('Failed to save builtin avatar image data (imagecopy).')); + } + + return PhabricatorImageTransformer::saveImageDataInAnyFormat( + $canvas, + 'image/png'); + } + + private static function rgba2gd($rgba) { + $r = $rgba[0]; + $g = $rgba[1]; + $b = $rgba[2]; + $a = $rgba[3]; + $a = (1 - $a) * 255; + return ($a << 24) | ($r << 16) | ($g << 8) | $b; } public static function getImageMap() { $root = dirname(phutil_get_library_root('phabricator')); $root = $root.'/resources/builtin/alphanumeric/'; $map = array(); - $list = Filesystem::listDirectory($root, $include_hidden = false); + $list = id(new FileFinder($root)) + ->withType('f') + ->withFollowSymlinks(true) + ->find(); + foreach ($list as $file) { - $key = 'alphanumeric/'.$file; - $map[$key] = $root.$file; + $map['alphanumeric/'.$file] = $root.$file; + } + return $map; + } + + public function getUniqueProfileImage($username) { + $pack_map = $this->getImagePackMap(); + $image_map = $this->getImageMap(); + $color_map = $this->getColorMap(); + $border_map = $this->getBorderMap(); + $file = phutil_utf8_strtoupper(substr($username, 0, 1)); + + $pack_count = count($pack_map); + $color_count = count($color_map); + $border_count = count($border_map); + + $pack_seed = $username.'_pack'; + $color_seed = $username.'_color'; + $border_seed = $username.'_border'; + + $pack_key = + PhabricatorHash::digestToRange($pack_seed, 1, $pack_count); + $color_key = + PhabricatorHash::digestToRange($color_seed, 1, $color_count); + $border_key = + PhabricatorHash::digestToRange($border_seed, 1, $border_count); + + $pack = $pack_map[$pack_key]; + $icon = 'alphanumeric/'.$pack.'/'.$file.'.png'; + $color = $color_map[$color_key]; + $border = $border_map[$border_key]; + + if (!isset($image_map[$icon])) { + $icon = 'alphanumeric/'.$pack.'/_default.png'; } + return array('color' => $color, 'icon' => $icon, 'border' => $border); + } + + public function getUserProfileImageFile($username) { + $unique = $this->getUniqueProfileImage($username); + + $composer = id(new self()) + ->setIcon($unique['icon']) + ->setColor($unique['color']) + ->setBorder($unique['border']); + + $data = $composer->loadBuiltinFileData(); + + $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); + $file = PhabricatorFile::newFromFileData( + $data, + array( + 'name' => $composer->getBuiltinDisplayName(), + 'profile' => true, + 'canCDN' => true, + )); + unset($unguarded); + + return $file; + } + + public static function getImagePackMap() { + $root = dirname(phutil_get_library_root('phabricator')); + $root = $root.'/resources/builtin/alphanumeric/'; + + $map = id(new FileFinder($root)) + ->withType('d') + ->withFollowSymlinks(false) + ->find(); + + return $map; + } + + public static function getBorderMap() { + + $map = array( + array(0, 0, 0, 0), + array(0, 0, 0, 0.3), + array(255, 255, 255, 0.4), + array(255, 255, 255, 0.7), + ); + return $map; } public static function getColorMap() { + // + // Generated Colors + // http://tools.medialab.sciences-po.fr/iwanthue/ + // $map = array( '#335862', - '#dfc47b', '#2d5192', - '#c0bc6e', '#3c5da0', '#99cd86', '#704889', '#5ac59e', '#984060', '#33d4d1', '#9c4050', '#20d8fd', '#944937', '#4bd0e3', '#a25542', '#4eb4f3', - '#705412', '#6da8ec', '#545608', '#829ce5', '#68681d', '#607bc2', - '#d1b66e', '#4b69ad', - '#a4a154', '#236ead', - '#daa969', '#31a0de', - '#996f31', '#4f8ed0', '#846f2a', '#bdb0f0', '#518342', '#9166aa', '#5e904e', '#f79dcc', '#158e6b', '#e189b7', '#3ba984', '#a85582', '#4cccb7', '#863d67', '#84c08c', '#7f4c7f', '#a1bb7a', '#65558f', - '#c2a962', '#445082', '#c9ca8e', '#265582', '#f4b189', '#265582', - '#bd8f50', '#40b8e1', '#814a28', '#80c8f6', '#cf7b5d', '#1db5c7', '#c0606e', '#299a89', '#ef8ead', '#296437', '#d39edb', '#507436', '#b888c9', '#476025', '#9987c5', - '#828136', '#7867a3', '#769b5a', '#c46e9d', '#437d4e', '#d17492', '#115e41', '#ec8794', '#297153', '#d67381', '#57c2c3', '#bc607f', '#86ceac', '#7e3e53', '#72c8b8', '#884349', '#45a998', '#faa38c', '#265582', - '#ad954f', '#265582', '#e4b788', '#265582', '#bbbc81', '#265582', '#ccb781', '#265582', '#eb957f', '#15729c', '#cf996f', '#369bc5', '#b6685d', '#2da0a1', '#d38275', '#217e70', '#ec9da1', '#146268', '#e8aa95', '#3c6796', '#8da667', '#935f93', '#69a573', '#ae78ad', '#569160', '#d898be', - '#525620', '#8eb4e8', '#5e622c', '#929ad3', '#6c8548', '#576196', '#aed0a0', '#694e79', '#9abb8d', '#8c5175', '#6bb391', '#8b4a5f', '#519878', '#ae7196', '#3d8465', '#e69eb3', '#48663d', '#cdaede', '#71743d', '#63acda', '#7b5d30', '#66bed6', - '#a66c4e', '#3585b0', - '#ba865c', '#5880b0', - '#9b864d', '#739acc', - '#9d764a', '#48a3ba', '#9d565b', '#7fc4ca', '#99566b', '#94cabf', '#7b4b49', '#b1c8eb', '#4e5632', '#ecb2c3', '#2d6158', '#cf8287', '#25889f', '#b2696d', '#6bafb6', '#8c5744', '#84b9d6', - '#725238', '#9db3d6', - '#816f3e', '#777cad', - '#a6a86e', '#826693', '#86a779', '#9d7fad', - '#8b8e55', '#b193c2', '#547348', '#d5adcb', '#3f674d', '#c98398', '#66865a', '#b2add6', '#5a623d', '#9793bb', - '#bea975', '#3c5472', '#d5c5a1', '#5e5a7f', - '#b09c68', '#2c647e', '#d8b194', '#49607f', '#c7b794', '#335862', '#e3aba7', '#335862', '#d9b9ad', '#335862', '#c48975', '#347b81', '#ad697e', '#799a6d', '#916b88', - '#aeb68d', '#69536b', '#b4c4ad', '#845865', '#96b89d', '#706d92', '#9aa27a', '#5b7292', '#bc967b', '#417792', '#ce9793', '#335862', '#c898a5', '#527a5f', '#b38ba9', '#648d72', '#986b78', '#79afa4', '#966461', '#50959b', '#b27d7a', '#335862', - '#b2a381', '#335862', '#bcadc4', '#706343', '#749ebc', '#8c6a50', '#92b8c4', - '#a07d62', '#758cad', '#868e67', '#335862', - '#b6978c', '#335862', - '#9e8f6e', '#335862', '#ac7e8b', '#77a185', '#807288', '#636f51', '#a192a9', '#467a70', '#9b7d73', '#335862', - '#8a7c5b', '#335862', '#8c9c85', '#335862', '#81645a', '#5f9489', '#335862', '#789da8', '#335862', '#72826c', '#335862', '#5c8596', '#335862', '#456a74', '#335862', '#335862', '#335862', ); return $map; } - public static function getBorderMap() { - $map = array( - 'rgba(0,0,0,.3);', // Darker - 'rgba(255,255,255,.5);', // Lighter - ); - return $map; - } - } diff --git a/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php b/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php index e64ab2e406..1532003122 100644 --- a/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php +++ b/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php @@ -1,278 +1,313 @@ getViewer(); $id = $request->getURIData('id'); $user = id(new PhabricatorPeopleQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->needProfileImage(true) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$user) { return new Aphront404Response(); } $this->setUser($user); $name = $user->getUserName(); $done_uri = '/p/'.$name.'/'; $supported_formats = PhabricatorFile::getTransformableImageFormats(); $e_file = true; $errors = array(); + // Verify install has GD extension, otherwise default to avatar.png + $gd = function_exists('imagecreatefromstring'); + if ($request->isFormPost()) { $phid = $request->getStr('phid'); $is_default = false; if ($phid == PhabricatorPHIDConstants::PHID_VOID) { - $phid = null; - $is_default = true; + // Compose the builtin unique image + if ($gd) { + $file = id(new PhabricatorFilesComposeAvatarBuiltinFile()) + ->getUserProfileImageFile($name); + } else { + $phid = null; + $is_default = true; + } + } else if ($phid) { $file = id(new PhabricatorFileQuery()) ->setViewer($viewer) ->withPHIDs(array($phid)) ->executeOne(); } else { if ($request->getFileExists('picture')) { $file = PhabricatorFile::newFromPHPUpload( $_FILES['picture'], array( 'authorPHID' => $viewer->getPHID(), 'canCDN' => true, )); } else { $e_file = pht('Required'); $errors[] = pht( 'You must choose a file when uploading a new profile picture.'); } } if (!$errors && !$is_default) { if (!$file->isTransformableImage()) { $e_file = pht('Not Supported'); $errors[] = pht( 'This server only supports these image formats: %s.', implode(', ', $supported_formats)); } else { $xform = PhabricatorFileTransform::getTransformByKey( PhabricatorFileThumbnailTransform::TRANSFORM_PROFILE); $xformed = $xform->executeTransform($file); } } if (!$errors) { if ($is_default) { $user->setProfileImagePHID(null); } else { $user->setProfileImagePHID($xformed->getPHID()); $xformed->attachToObject($user->getPHID()); } $user->save(); return id(new AphrontRedirectResponse())->setURI($done_uri); } } $title = pht('Edit Profile Picture'); $form = id(new PHUIFormLayoutView()) ->setUser($viewer); - $default_image = PhabricatorFile::loadBuiltin($viewer, 'profile.png'); + if ($gd) { + $unique_default = id(new PhabricatorFilesComposeAvatarBuiltinFile()) + ->getUniqueProfileImage($name); + $default_image = PhabricatorFile::loadBuiltin( + $viewer, $unique_default['icon']); + } else { + $unique_default = null; + $default_image = PhabricatorFile::loadBuiltin($viewer, 'profile.png'); + } $images = array(); $current = $user->getProfileImagePHID(); $has_current = false; if ($current) { $files = id(new PhabricatorFileQuery()) ->setViewer($viewer) ->withPHIDs(array($current)) ->execute(); if ($files) { $file = head($files); if ($file->isTransformableImage()) { $has_current = true; $images[$current] = array( 'uri' => $file->getBestURI(), 'tip' => pht('Current Picture'), ); } } } $builtins = array( 'user1.png', 'user2.png', 'user3.png', 'user4.png', 'user5.png', 'user6.png', 'user7.png', 'user8.png', 'user9.png', ); foreach ($builtins as $builtin) { $file = PhabricatorFile::loadBuiltin($viewer, $builtin); $images[$file->getPHID()] = array( 'uri' => $file->getBestURI(), 'tip' => pht('Builtin Image'), ); } // Try to add external account images for any associated external accounts. $accounts = id(new PhabricatorExternalAccountQuery()) ->setViewer($viewer) ->withUserPHIDs(array($user->getPHID())) ->needImages(true) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->execute(); foreach ($accounts as $account) { $file = $account->getProfileImageFile(); if ($account->getProfileImagePHID() != $file->getPHID()) { // This is a default image, just skip it. continue; } $provider = PhabricatorAuthProvider::getEnabledProviderByKey( $account->getProviderKey()); if ($provider) { $tip = pht('Picture From %s', $provider->getProviderName()); } else { $tip = pht('Picture From External Account'); } if ($file->isTransformableImage()) { $images[$file->getPHID()] = array( 'uri' => $file->getBestURI(), 'tip' => $tip, ); } } + $default_style = array(); + if ($unique_default) { + $border_color = implode(', ', $unique_default['border']); + $default_style = array( + 'background-color: '.$unique_default['color'].';', + 'border: 4px solid rgba('.$border_color.');', + 'height: 42px;', + 'width: 42px', + ); + } + $images[PhabricatorPHIDConstants::PHID_VOID] = array( 'uri' => $default_image->getBestURI(), 'tip' => pht('Default Picture'), + 'style' => implode(' ', $default_style), ); require_celerity_resource('people-profile-css'); Javelin::initBehavior('phabricator-tooltips', array()); $buttons = array(); foreach ($images as $phid => $spec) { + $style = null; + if (isset($spec['style'])) { + $style = $spec['style']; + } $button = javelin_tag( 'button', array( 'class' => 'grey profile-image-button', 'sigil' => 'has-tooltip', 'meta' => array( 'tip' => $spec['tip'], 'size' => 300, ), ), phutil_tag( 'img', array( 'height' => 50, 'width' => 50, 'src' => $spec['uri'], + 'style' => $style, ))); $button = array( phutil_tag( 'input', array( 'type' => 'hidden', 'name' => 'phid', 'value' => $phid, )), $button, ); $button = phabricator_form( $viewer, array( 'class' => 'profile-image-form', 'method' => 'POST', ), $button); $buttons[] = $button; } if ($has_current) { $form->appendChild( id(new AphrontFormMarkupControl()) ->setLabel(pht('Current Picture')) ->setValue(array_shift($buttons))); } $form->appendChild( id(new AphrontFormMarkupControl()) ->setLabel(pht('Use Picture')) ->setValue($buttons)); $form_box = id(new PHUIObjectBoxView()) ->setHeaderText($title) ->setFormErrors($errors) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setForm($form); $upload_form = id(new AphrontFormView()) ->setUser($viewer) ->setEncType('multipart/form-data') ->appendChild( id(new AphrontFormFileControl()) ->setName('picture') ->setLabel(pht('Upload Picture')) ->setError($e_file) ->setCaption( pht('Supported formats: %s', implode(', ', $supported_formats)))) ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton($done_uri) ->setValue(pht('Upload Picture'))); $upload_box = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Upload New Picture')) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setForm($upload_form); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Edit Profile Picture')); $crumbs->setBorder(true); $nav = $this->getProfileMenu(); $nav->selectFilter(PhabricatorPeopleProfileMenuEngine::ITEM_MANAGE); $header = $this->buildProfileHeader(); $view = id(new PHUITwoColumnView()) ->setHeader($header) ->addClass('project-view-home') ->addClass('project-view-people-home') ->setFooter(array( $form_box, $upload_box, )); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->setNavigation($nav) ->appendChild($view); } } diff --git a/src/applications/uiexample/examples/PhabricatorFilesComposeAvatarExample.php b/src/applications/uiexample/examples/PhabricatorFilesComposeAvatarExample.php index 8b408b3af0..6ea5537f9d 100644 --- a/src/applications/uiexample/examples/PhabricatorFilesComposeAvatarExample.php +++ b/src/applications/uiexample/examples/PhabricatorFilesComposeAvatarExample.php @@ -1,77 +1,91 @@ getRequest(); $viewer = $request->getUser(); $colors = PhabricatorFilesComposeAvatarBuiltinFile::getColorMap(); + $packs = PhabricatorFilesComposeAvatarBuiltinFile::getImagePackMap(); $builtins = PhabricatorFilesComposeAvatarBuiltinFile::getImageMap(); $borders = PhabricatorFilesComposeAvatarBuiltinFile::getBorderMap(); - shuffle($colors); $images = array(); foreach ($builtins as $builtin => $raw_file) { $file = PhabricatorFile::loadBuiltin($viewer, $builtin); $images[] = $file->getBestURI(); } $content = array(); + shuffle($colors); foreach ($colors as $color) { shuffle($borders); + $color_const = hexdec(trim($color, '#')); $border = head($borders); + $border_color = implode(', ', $border); $styles = array(); $styles[] = 'background-color: '.$color.';'; $styles[] = 'display: inline-block;'; - $styles[] = 'height: 46px;'; - $styles[] = 'width: 46px;'; + $styles[] = 'height: 42px;'; + $styles[] = 'width: 42px;'; $styles[] = 'border-radius: 3px;'; - $styles[] = 'border: 4px solid '.$border.';'; + $styles[] = 'border: 4px solid rgba('.$border_color.');'; shuffle($images); $png = head($images); $image = phutil_tag( 'img', array( 'src' => $png, - 'height' => 46, - 'width' => 46, + 'height' => 42, + 'width' => 42, )); $tag = phutil_tag( 'div', array( 'style' => implode(' ', $styles), ), $image); $content[] = phutil_tag( 'div', array( 'class' => 'mlr mlb', 'style' => 'float: left;', ), $tag); } + $count = new PhutilNumber( + count($colors) * count($builtins) * count($borders)); + + $infoview = id(new PHUIInfoView()) + ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) + ->appendChild(pht('This installation can generate %s unique '. + 'avatars. You can add additional image packs in '. + 'resources/builtins/alphanumeric/.', $count)); + + $info = phutil_tag_div('pmb', $infoview); $view = phutil_tag_div('ml', $content); return phutil_tag( 'div', array(), array( + $info, $view, )); } } diff --git a/src/infrastructure/util/PhabricatorHash.php b/src/infrastructure/util/PhabricatorHash.php index 00d7cca63c..7b5780460b 100644 --- a/src/infrastructure/util/PhabricatorHash.php +++ b/src/infrastructure/util/PhabricatorHash.php @@ -1,127 +1,142 @@ openEnvelope(); if (!$result) { throw new Exception(pht('Trying to digest empty password!')); } for ($ii = 0; $ii < 1000; $ii++) { $result = self::digest($result, $salt); } return $result; } /** * Digest a string for use in, e.g., a MySQL index. This produces a short * (12-byte), case-sensitive alphanumeric string with 72 bits of entropy, * which is generally safe in most contexts (notably, URLs). * * This method emphasizes compactness, and should not be used for security * related hashing (for general purpose hashing, see @{method:digest}). * * @param string Input string. * @return string 12-byte, case-sensitive alphanumeric hash of the string * which */ public static function digestForIndex($string) { $hash = sha1($string, $raw_output = true); static $map; if ($map === null) { $map = '0123456789'. 'abcdefghij'. 'klmnopqrst'. 'uvwxyzABCD'. 'EFGHIJKLMN'. 'OPQRSTUVWX'. 'YZ._'; } $result = ''; for ($ii = 0; $ii < self::INDEX_DIGEST_LENGTH; $ii++) { $result .= $map[(ord($hash[$ii]) & 0x3F)]; } return $result; } + public static function digestToRange($string, $min, $max) { + if ($min > $max) { + throw new Exception(pht('Maximum must be larger than minimum.')); + } + + if ($min == $max) { + return $min; + } + + $hash = sha1($string, $raw_output = true); + $value = head(unpack('L', $hash)); + + return $min + ($value % ($max - $min)); + } + /** * Shorten a string to a maximum byte length in a collision-resistant way * while retaining some degree of human-readability. * * This function converts an input string into a prefix plus a hash. For * example, a very long string beginning with "crabapplepie..." might be * digested to something like "crabapp-N1wM1Nz3U84k". * * This allows the maximum length of identifiers to be fixed while * maintaining a high degree of collision resistance and a moderate degree * of human readability. * * @param string The string to shorten. * @param int Maximum length of the result. * @return string String shortened in a collision-resistant way. */ public static function digestToLength($string, $length) { // We need at least two more characters than the hash length to fit in a // a 1-character prefix and a separator. $min_length = self::INDEX_DIGEST_LENGTH + 2; if ($length < $min_length) { throw new Exception( pht( 'Length parameter in %s must be at least %s, '. 'but %s was provided.', 'digestToLength()', new PhutilNumber($min_length), new PhutilNumber($length))); } // We could conceivably return the string unmodified if it's shorter than // the specified length. Instead, always hash it. This makes the output of // the method more recognizable and consistent (no surprising new behavior // once you hit a string longer than `$length`) and prevents an attacker // who can control the inputs from intentionally using the hashed form // of a string to cause a collision. $hash = self::digestForIndex($string); $prefix = substr($string, 0, ($length - ($min_length - 1))); return $prefix.'-'.$hash; } }