Profile: Use sharp to prerender the profile background
including the user image. Also introduces axios as a dependency
This commit is contained in:
@@ -41,7 +41,7 @@
|
|||||||
<text x="387.202px" y="200.273px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:12px;">DEV</text>
|
<text x="387.202px" y="200.273px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:12px;">DEV</text>
|
||||||
<text x="387.202px" y="212.666px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:12px;">CONTRIB</text>
|
<text x="387.202px" y="212.666px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:12px;">CONTRIB</text>
|
||||||
</g>
|
</g>
|
||||||
<g transform="matrix(2.31555,0,0,1.66192,-505.061,-60.4179)">
|
<g transform="matrix(2.31555,0,0,1.66192,-505.061,-78.2437)">
|
||||||
<text x="443.006px" y="119.692px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:12px;">{{PROFILE_TEXT}}</text>
|
<text x="443.006px" y="119.692px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:12px;">{{PROFILE_TEXT}}</text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
<g transform="matrix(0.166016,0,0,0.166016,499.979,0.476193)">
|
<g transform="matrix(0.166016,0,0,0.166016,499.979,0.476193)">
|
||||||
<use xlink:href="#_Image5" x="0" y="0" width="512px" height="512px"/>
|
<use xlink:href="#_Image5" x="0" y="0" width="512px" height="512px"/>
|
||||||
</g>
|
</g>
|
||||||
<g id="USER_IMAGE" transform="matrix(0.853333,0,0,0.853333,73.7407,8.57671)">
|
<g id="USER_IMAGE" transform="matrix(1.09227,0,0,1.09227,-12.8119,-1.02181)">
|
||||||
<circle cx="399.913" cy="77.84" r="58.594" style="fill:rgb(79,255,171);"/>
|
<circle cx="399.913" cy="77.84" r="58.594" style="fill:rgb(79,255,171);"/>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 91 KiB |
Binary file not shown.
@@ -1,6 +1,8 @@
|
|||||||
const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js");
|
const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js");
|
||||||
const { Card, User, Character } = require("../models");
|
const { Card, User, Character } = require("../models");
|
||||||
const { UserUtils, Compositing, Rendering } = require("../util");
|
const { UserUtils, Compositing, Rendering } = require("../util");
|
||||||
|
const axios = require("axios");
|
||||||
|
const sharp = require("sharp");
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
const pageSize = 8;
|
const pageSize = 8;
|
||||||
@@ -34,6 +36,16 @@ module.exports = {
|
|||||||
profileTemplate = profileTemplate.replace(/{{CC}}/g, await Card.count({where: {userId: user.id}}));
|
profileTemplate = profileTemplate.replace(/{{CC}}/g, await Card.count({where: {userId: user.id}}));
|
||||||
profileTemplate = profileTemplate.replace(/{{LVL}}/g, await user.level().currentLevel);
|
profileTemplate = profileTemplate.replace(/{{LVL}}/g, await user.level().currentLevel);
|
||||||
|
|
||||||
|
let userImageBuffer = await axios.get(discordUser.displayAvatarURL({format: 'png', size: 128}), { responseType: 'arraybuffer' });
|
||||||
|
userImage = await sharp(userImageBuffer.data);
|
||||||
|
const rect = new Buffer.from(
|
||||||
|
'<svg><rect x="0" y="0" width="128" height="128" rx="100%" ry="100%"/></svg>'
|
||||||
|
);
|
||||||
|
userImage = await userImage.composite([{input: rect, blend: 'dest-in' }]).png().toBuffer();
|
||||||
|
|
||||||
|
let background = await sharp(Buffer.from(profileTemplate, 'utf8'))
|
||||||
|
.composite([{ input: userImage, left: 360, top: 20 }]).png().toBuffer();
|
||||||
|
|
||||||
let slots = ['slotOne', 'slotTwo', 'slotThree', 'slotFour'];
|
let slots = ['slotOne', 'slotTwo', 'slotThree', 'slotFour'];
|
||||||
let renderedCards = [];
|
let renderedCards = [];
|
||||||
for (slot of slots) {
|
for (slot of slots) {
|
||||||
@@ -47,7 +59,7 @@ module.exports = {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let profileImage = await Compositing.renderProfile(profile, profileTemplate, renderedCards);
|
let profileImage = await Compositing.renderProfile(profile, background, renderedCards);
|
||||||
await interaction.editReply({ files: [profileImage] });
|
await interaction.editReply({ files: [profileImage] });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
43
package-lock.json
generated
43
package-lock.json
generated
@@ -10,6 +10,7 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discordjs/rest": "^0.3.0",
|
"@discordjs/rest": "^0.3.0",
|
||||||
|
"axios": "^0.27.2",
|
||||||
"discord-api-types": "^0.37.2",
|
"discord-api-types": "^0.37.2",
|
||||||
"discord.js": "^14.0.0",
|
"discord.js": "^14.0.0",
|
||||||
"dotenv": "^16.0.0",
|
"dotenv": "^16.0.0",
|
||||||
@@ -176,6 +177,15 @@
|
|||||||
"node": ">= 4.0.0"
|
"node": ">= 4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/axios": {
|
||||||
|
"version": "0.27.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
|
||||||
|
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.14.9",
|
||||||
|
"form-data": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
@@ -691,6 +701,25 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/follow-redirects": {
|
||||||
|
"version": "1.15.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
|
||||||
|
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"debug": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/form-data": {
|
"node_modules/form-data": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||||
@@ -2220,6 +2249,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
||||||
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="
|
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="
|
||||||
},
|
},
|
||||||
|
"axios": {
|
||||||
|
"version": "0.27.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
|
||||||
|
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
|
||||||
|
"requires": {
|
||||||
|
"follow-redirects": "^1.14.9",
|
||||||
|
"form-data": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
@@ -2629,6 +2667,11 @@
|
|||||||
"to-regex-range": "^5.0.1"
|
"to-regex-range": "^5.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"follow-redirects": {
|
||||||
|
"version": "1.15.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
|
||||||
|
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA=="
|
||||||
|
},
|
||||||
"form-data": {
|
"form-data": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discordjs/rest": "^0.3.0",
|
"@discordjs/rest": "^0.3.0",
|
||||||
|
"axios": "^0.27.2",
|
||||||
"discord-api-types": "^0.37.2",
|
"discord-api-types": "^0.37.2",
|
||||||
"discord.js": "^14.0.0",
|
"discord.js": "^14.0.0",
|
||||||
"dotenv": "^16.0.0",
|
"dotenv": "^16.0.0",
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ const { Card } = require('../models');
|
|||||||
//TODO: Handle missing images
|
//TODO: Handle missing images
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: "Compositing",
|
name: "Compositing",
|
||||||
renderProfile: async function(profile, svgTemplate, renderedCards) {
|
renderProfile: async function(profile, background, renderedCards) {
|
||||||
let hash = crypto.createHash('md5').update(JSON.stringify(profile) + svgTemplate).digest('hex');
|
let hash = crypto.createHash('md5').update(JSON.stringify(profile) + background).digest('hex');
|
||||||
|
|
||||||
let outFile = `/app/assets/image_cache/profiles/${hash}.gif`;
|
let outFile = `/app/assets/image_cache/profiles/${hash}.gif`;
|
||||||
console.log('Rendering profile to ' + outFile);
|
console.log('Rendering profile to ' + outFile);
|
||||||
|
|
||||||
//composite {overlay} {background} [{mask}] [-compose {method}] {result}
|
//composite {overlay} {background} [{mask}] [-compose {method}] {result}
|
||||||
let args = ['svg:-', 'null:',
|
let args = ['png:-', 'null:',
|
||||||
'\(', `${renderedCards[0]}`, '-coalesce', '\)',
|
'\(', `${renderedCards[0]}`, '-coalesce', '\)',
|
||||||
'-geometry', '+25+85', '-compose', 'over', '-layers', 'composite',
|
'-geometry', '+25+85', '-compose', 'over', '-layers', 'composite',
|
||||||
'null:', '\(', `${renderedCards[1]}`, '-coalesce', '-resize', '170x283', '\)',
|
'null:', '\(', `${renderedCards[1]}`, '-coalesce', '-resize', '170x283', '\)',
|
||||||
@@ -27,7 +27,7 @@ module.exports = {
|
|||||||
console.log('GM Args: ' + args);
|
console.log('GM Args: ' + args);
|
||||||
|
|
||||||
const composite = spawn('convert', args);
|
const composite = spawn('convert', args);
|
||||||
composite.stdin.write(svgTemplate);
|
composite.stdin.write(background);
|
||||||
composite.stdin.end();
|
composite.stdin.end();
|
||||||
|
|
||||||
composite.stderr.on('data', (data) => {
|
composite.stderr.on('data', (data) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user