ランダムにアバターを生成するように
This commit is contained in:
		
							parent
							
								
									d2d991ff34
								
							
						
					
					
						commit
						18bc4a49e8
					
				|  | @ -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", | ||||||
|  |  | ||||||
|  | @ -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(); | ||||||
|  | } | ||||||
|  | @ -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 | 
|  | @ -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'); | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue