diff --git a/assets/profile/profile.svg b/assets/profile/profile.svg
index 0a56ded..0dcb2eb 100644
--- a/assets/profile/profile.svg
+++ b/assets/profile/profile.svg
@@ -41,7 +41,7 @@
DEV
CONTRIB
-
+
{{PROFILE_TEXT}}
@@ -72,7 +72,7 @@
-
+
diff --git a/assets/profile/template.afdesign b/assets/profile/template.afdesign
index d6b05bf..5412b94 100644
Binary files a/assets/profile/template.afdesign and b/assets/profile/template.afdesign differ
diff --git a/commands/profile.js b/commands/profile.js
index 1fe1a08..4f47bce 100644
--- a/commands/profile.js
+++ b/commands/profile.js
@@ -1,6 +1,8 @@
const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js");
const { Card, User, Character } = require("../models");
const { UserUtils, Compositing, Rendering } = require("../util");
+const axios = require("axios");
+const sharp = require("sharp");
const fs = require('fs');
const pageSize = 8;
@@ -34,6 +36,16 @@ module.exports = {
profileTemplate = profileTemplate.replace(/{{CC}}/g, await Card.count({where: {userId: user.id}}));
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(
+ ''
+ );
+ 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 renderedCards = [];
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] });
}
}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 81dbfb3..3ab6159 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,6 +10,7 @@
"license": "ISC",
"dependencies": {
"@discordjs/rest": "^0.3.0",
+ "axios": "^0.27.2",
"discord-api-types": "^0.37.2",
"discord.js": "^14.0.0",
"dotenv": "^16.0.0",
@@ -176,6 +177,15 @@
"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": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -691,6 +701,25 @@
"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": {
"version": "4.0.0",
"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",
"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": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -2629,6 +2667,11 @@
"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": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
diff --git a/package.json b/package.json
index ff27935..c1a1386 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
"license": "ISC",
"dependencies": {
"@discordjs/rest": "^0.3.0",
+ "axios": "^0.27.2",
"discord-api-types": "^0.37.2",
"discord.js": "^14.0.0",
"dotenv": "^16.0.0",
diff --git a/util/compositing.js b/util/compositing.js
index 43d57b4..eb660db 100644
--- a/util/compositing.js
+++ b/util/compositing.js
@@ -6,14 +6,14 @@ const { Card } = require('../models');
//TODO: Handle missing images
module.exports = {
name: "Compositing",
- renderProfile: async function(profile, svgTemplate, renderedCards) {
- let hash = crypto.createHash('md5').update(JSON.stringify(profile) + svgTemplate).digest('hex');
+ renderProfile: async function(profile, background, renderedCards) {
+ let hash = crypto.createHash('md5').update(JSON.stringify(profile) + background).digest('hex');
let outFile = `/app/assets/image_cache/profiles/${hash}.gif`;
console.log('Rendering profile to ' + outFile);
//composite {overlay} {background} [{mask}] [-compose {method}] {result}
- let args = ['svg:-', 'null:',
+ let args = ['png:-', 'null:',
'\(', `${renderedCards[0]}`, '-coalesce', '\)',
'-geometry', '+25+85', '-compose', 'over', '-layers', 'composite',
'null:', '\(', `${renderedCards[1]}`, '-coalesce', '-resize', '170x283', '\)',
@@ -27,7 +27,7 @@ module.exports = {
console.log('GM Args: ' + args);
const composite = spawn('convert', args);
- composite.stdin.write(svgTemplate);
+ composite.stdin.write(background);
composite.stdin.end();
composite.stderr.on('data', (data) => {