first commit

This commit is contained in:
zzc
2026-01-09 11:21:29 +08:00
commit 24e6484860
29 changed files with 1930 additions and 0 deletions

120
util/image.js Normal file
View File

@@ -0,0 +1,120 @@
const { createCanvas, loadImage, registerFont } = require("canvas");
const fs = require("fs");
const path = require("path");
registerFont(path.join(process.cwd(), `/public/font/PINGFANG MEDIUM.TTF`), {
family: "pf",
});
const mergeImage = async (name) => {
const WIDTH = 1080;
const HEIGHT = 1920;
const canvas = createCanvas(WIDTH, HEIGHT);
const context = canvas.getContext("2d");
const bg = await loadImage(
path.join(process.cwd(), "/public/merge/base_card1.jpg")
);
context.drawImage(bg, 0, 0, 1080, 1920);
context.font = "48px px";
context.fillStyle = "#282828";
context.textAlign = "center"; //文字水平居中
context.fillText(name, 566 / 2, 422);
context.font = `400 80px pf`;
context.textAlign = "center";
context.fillStyle = "red";
context.fillText(`龙马精神`, WIDTH / 2, 366 + 4);
// return canvas.toBuffer();
const out = fs.createWriteStream(__dirname + "/test2.png");
const stream = canvas.createPNGStream();
stream.pipe(out);
out.on("finish", () => console.log("The PNG file was created."));
};
// const avatarOrnament = async (avatarPath, ornamentPath, size = 512) => {
// // 1⃣ 加载图片
// const avatarImg = await loadImage(avatarPath);
// const ornamentImg = await loadImage(ornamentPath);
// const width = avatarImg.width;
// const height = avatarImg.height;
// const canvas = createCanvas(width, height);
// const ctx = canvas.getContext("2d");
// // 3⃣ 先画头像
// ctx.drawImage(avatarImg, 0, 0, width, height);
// // 4⃣ 计算挂饰尺寸(取短边的 25%
// const baseSize = Math.min(width, height);
// const ornamentSize = Math.floor(baseSize * 0.25);
// const ornamentRatio = ornamentImg.width / ornamentImg.height;
// const ornamentWidth =
// ornamentRatio >= 1 ? ornamentSize : ornamentSize * ornamentRatio;
// const ornamentHeight =
// ornamentRatio >= 1 ? ornamentSize / ornamentRatio : ornamentSize;
// // 5⃣ 位置:右下角 + 内边距
// const padding = Math.floor(baseSize * 0.05);
// const x = width - ornamentWidth - padding;
// const y = height - ornamentHeight - padding;
// // 6⃣ 阴影(非常关键:让合成“自然”)
// ctx.save();
// ctx.shadowColor = "rgba(0, 0, 0, 0.25)";
// ctx.shadowBlur = Math.floor(baseSize * 0.03);
// ctx.shadowOffsetX = Math.floor(baseSize * 0.01);
// ctx.shadowOffsetY = Math.floor(baseSize * 0.01);
// ctx.drawImage(ornamentImg, x, y, ornamentWidth, ornamentHeight);
// ctx.restore();
// // 6. 输出文件
// // const buffer = canvas.toBuffer("image/png");
// // fs.writeFileSync(outputPath, buffer);
// const out = fs.createWriteStream(__dirname + "/test3.png");
// const stream = canvas.createPNGStream();
// stream.pipe(out);
// out.on("finish", () => console.log("The PNG file was created."));
// return "success";
// };
const avatarOrnament = async (avatarPath, ornamentPath, size = 512) => {
// 1. 读取头像
const avatar = await loadImage(avatarPath);
// 2. Canvas 尺寸 = 头像尺寸(不裁剪)
const width = 500;
const height = 500;
const canvas = createCanvas(width, height);
const ctx = canvas.getContext("2d");
// 3. 绘制头像
ctx.drawImage(avatar, 0, 0, width, height);
// 4. 读取装饰外框PNG透明
// const frame = await loadImage(ornamentPath);
const framePath = path.resolve(__dirname + "/66.png");
const frame = await loadImage(framePath);
// 5. 覆盖绘制外框
ctx.drawImage(frame, 0, 0, width, height);
// 6. 输出文件
// const buffer = canvas.toBuffer("image/png");
// fs.writeFileSync(outputPath, buffer);
const out = fs.createWriteStream(__dirname + "/test6.png");
const stream = canvas.createPNGStream();
stream.pipe(out);
out.on("finish", () => console.log("The PNG file was created."));
return "success";
};
module.exports = {
mergeImage,
avatarOrnament,
};