ランダムにアバターを生成するように
This commit is contained in:
		
							parent
							
								
									d2d991ff34
								
							
						
					
					
						commit
						18bc4a49e8
					
				|  | @ -75,6 +75,7 @@ | |||
| 		"@types/portscanner": "2.1.0", | ||||
| 		"@types/pug": "2.0.4", | ||||
| 		"@types/qrcode": "1.3.2", | ||||
| 		"@types/random-seed": "0.3.3", | ||||
| 		"@types/ratelimiter": "2.1.28", | ||||
| 		"@types/redis": "2.8.12", | ||||
| 		"@types/rename": "1.0.1", | ||||
|  | @ -103,6 +104,7 @@ | |||
| 		"bootstrap-vue": "2.0.0-rc.13", | ||||
| 		"bull": "3.7.0", | ||||
| 		"cafy": "15.1.1", | ||||
| 		"canvas": "2.4.1", | ||||
| 		"chai": "4.2.0", | ||||
| 		"chalk": "2.4.2", | ||||
| 		"cli-highlight": "2.1.0", | ||||
|  | @ -188,6 +190,7 @@ | |||
| 		"pug": "2.0.3", | ||||
| 		"punycode": "2.1.1", | ||||
| 		"qrcode": "1.3.3", | ||||
| 		"random-seed": "0.3.0", | ||||
| 		"randomcolor": "0.5.4", | ||||
| 		"ratelimiter": "3.3.0", | ||||
| 		"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 rap from '@prezzemolo/rap'; | ||||
| import { ensure } from '../../prelude/ensure'; | ||||
| import config from '../../config'; | ||||
| 
 | ||||
| @EntityRepository(User) | ||||
| export class UserRepository extends Repository<User> { | ||||
|  | @ -88,7 +89,7 @@ export class UserRepository extends Repository<User> { | |||
| 			name: user.name, | ||||
| 			username: user.username, | ||||
| 			host: user.host, | ||||
| 			avatarUrl: user.avatarUrl, | ||||
| 			avatarUrl: user.avatarUrl ? user.avatarUrl : config.url + '/avatar/' + user.id, | ||||
| 			avatarColor: user.avatarColor, | ||||
| 			isAdmin: user.isAdmin || 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
 | ||||
| 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 => { | ||||
| 	const file = fs.createReadStream(`${__dirname}/assets/dummy.png`); | ||||
| 	ctx.set('Content-Type', 'image/jpeg'); | ||||
|  |  | |||
|  | @ -25,6 +25,7 @@ import Logger from '../services/logger'; | |||
| import { program } from '../argv'; | ||||
| import { UserProfiles } from '../models'; | ||||
| import { networkChart } from '../services/chart'; | ||||
| import { genAvatar } from '../misc/gen-avatar'; | ||||
| 
 | ||||
| export const serverLogger = new Logger('server', 'gray', false); | ||||
| 
 | ||||
|  | @ -72,6 +73,12 @@ router.use(activityPub.routes()); | |||
| router.use(nodeinfo.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 => { | ||||
| 	const profile = await UserProfiles.findOne({ | ||||
| 		emailVerifyCode: ctx.params.code | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue