import sharp from "sharp"; import {Logger} from "../logging/logger.js"; import fs from "fs"; export class NameCardCreator { constructor(templatePath) { this.templatePath = templatePath; this.fontPath = "./wwwroot/assets/fonts/Fredoka/Fredoka-VariableFont_wdth,wght.ttf"; this.fontData = this.loadFontData(); } /** * Loads the template file into a sharp instance * @returns {sharp.Sharp} sharp image object */ loadTemplate() { return sharp(this.templatePath); } /** * Combines a template image with a user avatar and saves it * @param avatarPath {string} * @param name {string} * @returns {Promise} resulting image buffer */ async getWelcomeCard(avatarPath, name) { try{ const template = this.loadTemplate(); const avatar = await this.handleAvatar(avatarPath); const messageBuffer = await this.getMessageBuffer(`Hello ${name}!`); const result = await template .composite([ { input: avatar, top: 215, left: 275 }, { input: messageBuffer, top: 400, left: 1300 } ]) .toFile("namecard.png") console.log("✅ Welcome card created: welcome-card.png"); return result; } catch(err) { console.log(err); await Logger.error("Unable to create name card", err); } } /** * * @param avatarPath * @returns {Promise>} */ async handleAvatar(avatarPath) { const avatarSize = 670; const borderSize = 8; const radius = avatarSize / 2; const totalSize = avatarSize + borderSize * 2; const avatarBuffer = await sharp(avatarPath) .resize(avatarSize, avatarSize, { fit: "cover" }) .png() .toBuffer(); const maskSvg = Buffer.from(` `); const roundedAvatar = await sharp(avatarBuffer) .composite([{ input: maskSvg, blend: "dest-in" }]) .png() .toBuffer(); const roundedBorder = Buffer.from(` `) return await sharp({ create: { width: totalSize, height: totalSize, channels: 4, background: "#0000" } }).composite([ { input: roundedAvatar, top: 0, left: 0 }, { input: roundedBorder, top: borderSize, left: borderSize } ]) .png() .toBuffer(); } async getMessageBuffer(message){ const messageSvg = this.getMessageSvg(message); return Buffer.from(messageSvg, "utf-8"); } /** * * @param message {string} * @returns {string} */ getMessageSvg(message) { const safeMessage = message .replace(/&/g, "&") .replace(//g, ">"); return ` ${safeMessage} `; } loadFontData(){ return fs.readFileSync(this.fontPath).toString("base64"); } }