import { createCanvas, loadImage, registerFont } from "canvas"; import { writeFileSync } from "fs"; import sharp from "sharp"; import { MiQOptions } from "./miq"; function textReplace( text: string ) { let result = ""; // 改行削除 text = text.replaceAll("\n", ""); // 10文字/1回で改行を追加 let maxLength = 10; if (text.length > maxLength) { for (let i = 0; i < text.length; i += maxLength) { result += text.substring(i, i + maxLength) + "\n"; } result = result.trimEnd(); } // 80文字以上は「...」で省略 maxLength = 80; if (result.length > maxLength) { result = result.substring(0, maxLength) + "..."; } return result; } async function iconReplace( color: boolean, iconURL: string, ) { let result = ""; const buffer = await(await fetch(iconURL, { method: "GET", cache: "no-store", })).arrayBuffer(); if (color) { const img = await sharp(Buffer.from(buffer)) .png() .toBuffer(); result = `data:image/png;base64,${img.toString("base64")}`; } else { const img = await sharp(Buffer.from(buffer)) .png() .grayscale() .toBuffer(); result = `data:image/png;base64,${img.toString("base64")}`; } return result; } /** * A function to generate * Make it a quote on Node.js. */ export default async function MiQ({ type, color, text, iconURL, userName, userID, }: MiQOptions) { // フォント読み込み registerFont("miq/fonts/NotoSansJP.ttf", { family: "Noto Sans JP" }); // 初期化 const canvas = createCanvas(1200, 630); const ctx = canvas.getContext("2d"); // 背景描画 ctx.fillStyle = "black"; ctx.fillRect(0, 0, canvas.width, canvas.height); // アイコン描画 const iconImg = await loadImage(await iconReplace( color, iconURL, )); const iconSize = canvas.height; ctx.drawImage(iconImg, 0, 0, iconSize, iconSize); // ユーザー名描画 ctx.font = "38px Noto Sans JP"; ctx.fillStyle = "white"; ctx.textAlign = "left"; ctx.textBaseline = "middle"; let x = 670; let y = 480; ctx.fillText("-", x, y); ctx.fillText(userName, x+40, y, canvas.width-(x+40)); // ユーザーID描画 ctx.font = "28px Noto Sans JP"; ctx.fillStyle = "#3c3c3c"; ctx.fillText(`@${userID}`, x+120, y+50, canvas.width-(x+120)); // 本文描画 ctx.font = "48px Noto Sans JP"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillStyle = "white"; text = textReplace(text); x = 870; y = 30; ctx.fillText(text, x, y+50); // フェード描画 const fadeColor = "black"; const gradient = ctx.createLinearGradient(0, 0, canvas.width, 0); gradient.addColorStop(0, "rgba(0, 0, 0, 0)"); gradient.addColorStop(0.5, fadeColor); ctx.fillStyle = gradient; ctx.fillRect(0, 0, iconSize, canvas.height); // 返答 if (type === "Buffer") { return canvas.toBuffer(); } else if (type === "Base64") { return canvas.toDataURL(); } else { return "Error: The type property is invalid."; } }