fix: font

This commit is contained in:
zzc
2026-02-01 16:49:23 +08:00
parent 9dfa72707a
commit 6bc0a2b85f

View File

@@ -863,6 +863,9 @@ const saveByCanvas = async (save = true) => {
});
};
// 辅助函数rpx 转 px (基于预览容器宽度 506rpx 对应 Canvas 540px)
const r2p = (rpx) => (rpx * 540) / 506;
try {
// 1⃣ 画背景
// ⭐ 先加载背景图
@@ -874,40 +877,52 @@ const saveByCanvas = async (save = true) => {
ctx.drawImage(bgImg, 0, 0, W, H);
// 2⃣ 半透明遮罩(和你 UI 一致)
// 2⃣ 半透明遮罩
ctx.fillStyle = "rgba(0,0,0,0.08)";
ctx.fillRect(0, 0, W, H);
// 3⃣ 标题图片
if (titleImg) {
const titleW = titleImg.width * titleScale.value;
const titleH = titleImg.height * titleScale.value;
const titleX = (W - titleW) / 2 + titleOffsetX.value;
const titleY = 40 + titleOffsetY.value;
ctx.drawImage(titleImg, titleX, titleY, titleW, titleH);
const previewBaseWidth = 400; // rpx
const drawWidth = r2p(previewBaseWidth) * titleScale.value;
const drawHeight = (titleImg.height / titleImg.width) * drawWidth;
// 预览中是 translate(offsetX, offsetY)top: 40rpx
const titleX = (W - drawWidth) / 2 + r2p(titleOffsetX.value);
const titleY = r2p(40 + titleOffsetY.value);
ctx.drawImage(titleImg, titleX, titleY, drawWidth, drawHeight);
}
// 4⃣ 祝福语气泡
// 预览中 .bubble 有 padding: 40rpx且 .card-overlay 有 padding: 30rpx
// 意味着文字距离容器边缘至少有 70rpx
drawBubbleText(ctx, {
text: targetName.value + "\n " + blessingText.value.content,
x: 70,
y: 260 + bubbleOffsetY.value,
maxWidth: bubbleMaxWidth.value, // 使用动态宽度
canvasWidth: W, // 传入画布宽度以实现自动居中
fontSize: fontSize.value,
lineHeight: fontSize.value * 1.5,
backgroundColor: "rgba(255,255,255,0.85)",
x: 0,
y: r2p(230 + bubbleOffsetY.value),
maxWidth: r2p(bubbleMaxWidth.value), // 预览中 bubble-text 的宽度
canvasWidth: W,
fontSize: r2p(fontSize.value),
lineHeight: r2p(fontSize.value * 1.6), // 预览中是 1.6
padding: r2p(40 + 30), // 内部 padding 40 + 容器 padding 30
backgroundColor: "transparent",
textColor: selectedColor.value,
fontFamily: selectedFont.value.family,
});
// 5⃣ 用户信息
// 预览中 user 是 absolute, left: 160 + offsetX, bottom: 40 - offsetY
drawUserBubble(ctx, {
x: 160 + userOffsetX.value,
y: H - 136 + userOffsetY.value,
avatarImg: avatarImg, // 传入 Image 对象
x: r2p(160 + userOffsetX.value),
bottom: r2p(40 - userOffsetY.value),
canvasHeight: H,
avatarImg: avatarImg,
username: signatureName.value,
desc: "送上祝福",
textColor: signatureColor.value,
avatarSize: r2p(64),
padding: r2p(15),
fontSizeName: r2p(24),
fontSizeDesc: r2p(20),
});
// 6⃣ 输出
@@ -1012,40 +1027,26 @@ function drawBubbleText(ctx, options) {
});
// 如果提供了 canvasWidth则自动计算居中的 x 坐标
// 预览中文字是左对齐,但整个气泡容器是水平居中的
let drawX = x;
if (canvasWidth) {
const totalWidth = maxLineWidth + padding * 2;
drawX = (canvasWidth - totalWidth) / 2;
drawX = (canvasWidth - maxLineWidth) / 2;
}
// 2⃣ 计算气泡尺寸
// const bubbleWidth = maxWidth
// const bubbleHeight = lines.length * lineHeight + padding * 2
// 3⃣ 绘制气泡(圆角矩形)
// drawRoundRect(
// ctx,
// drawX,
// y,
// bubbleWidth,
// bubbleHeight,
// radius,
// backgroundColor
// )
// 4⃣ 绘制文字
ctx.fillStyle = textColor;
lines.forEach((line, index) => {
ctx.fillText(line, drawX + padding, y + padding + index * lineHeight);
ctx.fillText(line, drawX, y + padding + index * lineHeight);
});
}
function drawUserBubble(ctx, options) {
const {
x = 40, // 气泡起点 x
y = 860, // 气泡起点 y
y, // 气泡起点 y (如果传了 bottom 则优先计算)
bottom, // 距离底部的距离
canvasHeight,
avatarImg, // CanvasImage 对象
username = "zzc",
desc = "送上祝福",
@@ -1072,11 +1073,17 @@ function drawUserBubble(ctx, options) {
Math.max(avatarSize, fontSizeName + fontSizeDesc + 4) + padding * 2;
const bubbleWidth = avatarSize + padding + textWidth + padding * 2;
// 计算 y
let drawY = y;
if (typeof bottom !== "undefined" && canvasHeight) {
drawY = canvasHeight - bottom - bubbleHeight;
}
// 1⃣ 绘制气泡(左右半圆)
drawRoundRect(
ctx,
x,
y,
drawY,
bubbleWidth,
bubbleHeight,
bubbleHeight / 2,
@@ -1085,7 +1092,7 @@ function drawUserBubble(ctx, options) {
// 2⃣ 绘制头像
const avatarX = x + padding;
const avatarY = y + (bubbleHeight - avatarSize) / 2;
const avatarY = drawY + (bubbleHeight - avatarSize) / 2;
ctx.save();
ctx.beginPath();
@@ -1104,7 +1111,7 @@ function drawUserBubble(ctx, options) {
// 3⃣ 绘制文字
const textX = avatarX + avatarSize + padding;
const textY = y + padding;
const textY = drawY + padding;
ctx.fillStyle = textColor;
ctx.font = `${fontSizeName}px 'PingFang SC'`;
ctx.fillText(username, textX, textY);