ランダムにアバターを生成するように

This commit is contained in:
syuilo 2019-04-15 20:37:21 +09:00
parent d2d991ff34
commit 18bc4a49e8
No known key found for this signature in database
GPG key ID: BDC4C49D06AB9D69
6 changed files with 101 additions and 7 deletions

View file

@ -75,6 +75,7 @@
"@types/portscanner": "2.1.0", "@types/portscanner": "2.1.0",
"@types/pug": "2.0.4", "@types/pug": "2.0.4",
"@types/qrcode": "1.3.2", "@types/qrcode": "1.3.2",
"@types/random-seed": "0.3.3",
"@types/ratelimiter": "2.1.28", "@types/ratelimiter": "2.1.28",
"@types/redis": "2.8.12", "@types/redis": "2.8.12",
"@types/rename": "1.0.1", "@types/rename": "1.0.1",
@ -103,6 +104,7 @@
"bootstrap-vue": "2.0.0-rc.13", "bootstrap-vue": "2.0.0-rc.13",
"bull": "3.7.0", "bull": "3.7.0",
"cafy": "15.1.1", "cafy": "15.1.1",
"canvas": "2.4.1",
"chai": "4.2.0", "chai": "4.2.0",
"chalk": "2.4.2", "chalk": "2.4.2",
"cli-highlight": "2.1.0", "cli-highlight": "2.1.0",
@ -188,6 +190,7 @@
"pug": "2.0.3", "pug": "2.0.3",
"punycode": "2.1.1", "punycode": "2.1.1",
"qrcode": "1.3.3", "qrcode": "1.3.3",
"random-seed": "0.3.0",
"randomcolor": "0.5.4", "randomcolor": "0.5.4",
"ratelimiter": "3.3.0", "ratelimiter": "3.3.0",
"recaptcha-promise": "0.1.3", "recaptcha-promise": "0.1.3",

89
src/misc/gen-avatar.ts Normal file
View file

@ -0,0 +1,89 @@
/**
* Random avatar generator
*/
import { createCanvas } from 'canvas';
import * as gen from 'random-seed';
const size = 512; // px
const n = 5; // resolution
const margin = (size / n) / 1.5;
const colors = [
'#e57373',
'#F06292',
'#BA68C8',
'#9575CD',
'#7986CB',
'#64B5F6',
'#4FC3F7',
'#4DD0E1',
'#4DB6AC',
'#81C784',
'#8BC34A',
'#AFB42B',
'#F57F17',
'#FF5722',
'#795548',
'#455A64',
];
const bg = '#e9e9e9';
const actualSize = size - (margin * 2);
const cellSize = actualSize / n;
const sideN = Math.floor(n / 2);
/**
* Generate buffer of random avatar by seed
*/
export function genAvatar(seed: string) {
const rand = gen.create(seed);
const canvas = createCanvas(size, size);
const ctx = canvas.getContext('2d');
ctx.fillStyle = bg;
ctx.beginPath();
ctx.fillRect(0, 0, size, size);
ctx.fillStyle = colors[rand(colors.length)];
// side bitmap (filled by false)
const side: boolean[][] = new Array(sideN);
for (let i = 0; i < side.length; i++) {
side[i] = new Array(n).fill(false);
}
// 1*n (filled by false)
const center: boolean[] = new Array(n).fill(false);
// tslint:disable-next-line:prefer-for-of
for (let x = 0; x < side.length; x++) {
for (let y = 0; y < side[x].length; y++) {
side[x][y] = rand(3) === 0;
}
}
for (let i = 0; i < center.length; i++) {
center[i] = rand(3) === 0;
}
// Draw
for (let x = 0; x < n; x++) {
for (let y = 0; y < n; y++) {
const isXCenter = x === ((n - 1) / 2);
if (isXCenter && !center[y]) continue;
const isLeftSide = x < ((n - 1) / 2);
if (isLeftSide && !side[x][y]) continue;
const isRightSide = x > ((n - 1) / 2);
if (isRightSide && !side[sideN - (x - sideN)][y]) continue;
const actualX = margin + (cellSize * x);
const actualY = margin + (cellSize * y);
ctx.beginPath();
ctx.fillRect(actualX, actualY, cellSize, cellSize);
}
}
return canvas.toBuffer();
}

View file

@ -3,6 +3,7 @@ import { User, ILocalUser, IRemoteUser } from '../entities/user';
import { Emojis, Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles } from '..'; import { Emojis, Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles } from '..';
import rap from '@prezzemolo/rap'; import rap from '@prezzemolo/rap';
import { ensure } from '../../prelude/ensure'; import { ensure } from '../../prelude/ensure';
import config from '../../config';
@EntityRepository(User) @EntityRepository(User)
export class UserRepository extends Repository<User> { export class UserRepository extends Repository<User> {
@ -88,7 +89,7 @@ export class UserRepository extends Repository<User> {
name: user.name, name: user.name,
username: user.username, username: user.username,
host: user.host, host: user.host,
avatarUrl: user.avatarUrl, avatarUrl: user.avatarUrl ? user.avatarUrl : config.url + '/avatar/' + user.id,
avatarColor: user.avatarColor, avatarColor: user.avatarColor,
isAdmin: user.isAdmin || undefined, isAdmin: user.isAdmin || undefined,
isBot: user.isBot || undefined, isBot: user.isBot || undefined,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -21,12 +21,6 @@ app.use(async (ctx, next) => {
// Init router // Init router
const router = new Router(); const router = new Router();
router.get('/default-avatar.jpg', ctx => {
const file = fs.createReadStream(`${__dirname}/assets/avatar.jpg`);
ctx.set('Content-Type', 'image/jpeg');
ctx.body = file;
});
router.get('/app-default.jpg', ctx => { router.get('/app-default.jpg', ctx => {
const file = fs.createReadStream(`${__dirname}/assets/dummy.png`); const file = fs.createReadStream(`${__dirname}/assets/dummy.png`);
ctx.set('Content-Type', 'image/jpeg'); ctx.set('Content-Type', 'image/jpeg');

View file

@ -25,6 +25,7 @@ import Logger from '../services/logger';
import { program } from '../argv'; import { program } from '../argv';
import { UserProfiles } from '../models'; import { UserProfiles } from '../models';
import { networkChart } from '../services/chart'; import { networkChart } from '../services/chart';
import { genAvatar } from '../misc/gen-avatar';
export const serverLogger = new Logger('server', 'gray', false); export const serverLogger = new Logger('server', 'gray', false);
@ -72,6 +73,12 @@ router.use(activityPub.routes());
router.use(nodeinfo.routes()); router.use(nodeinfo.routes());
router.use(wellKnown.routes()); router.use(wellKnown.routes());
router.get('/avatar/:x', ctx => {
const avatar = genAvatar(ctx.params.x);
ctx.set('Content-Type', 'image/png');
ctx.body = avatar;
});
router.get('/verify-email/:code', async ctx => { router.get('/verify-email/:code', async ctx => {
const profile = await UserProfiles.findOne({ const profile = await UserProfiles.findOne({
emailVerifyCode: ctx.params.code emailVerifyCode: ctx.params.code