feat: 背面图案支持 + 大小王素材位置微调 + 10号牌pip修复

This commit is contained in:
Poker Design Developer
2026-06-01 21:48:51 +08:00
parent f64c94a2f4
commit b0cdd8c3ad
6 changed files with 324 additions and 37 deletions

View File

@@ -271,15 +271,30 @@ async function drawJokerBody(ctx, w, h, which, design, project) {
}
if (img && img.complete && img.naturalWidth) {
const ratio = img.naturalWidth / img.naturalHeight
const target = bodyW / bodyH
const halfH = bodyH / 2
const imgRatio = img.naturalWidth / img.naturalHeight
const target = bodyW / halfH
let drawW, drawH
if (ratio > target) {
drawW = bodyW; drawH = bodyW / ratio
if (imgRatio > target) {
drawW = bodyW; drawH = bodyW / imgRatio
} else {
drawH = bodyH; drawW = bodyH * ratio
drawH = halfH; drawW = halfH * imgRatio
}
ctx.drawImage(img, padX + (bodyW - drawW) / 2, padTop + (bodyH - drawH) / 2, drawW, drawH)
const imageDx = Number(design.image_dx) || 0
const imageDy = Number(design.image_dy) || 0
const imageScale = Number(design.image_scale) || 1
const finalW = Math.max(1, drawW * imageScale)
const finalH = Math.max(1, drawH * imageScale)
const offsetX = bodyW * imageDx
const offsetY = bodyH * imageDy
const topX = padX + offsetX + (bodyW - finalW) / 2
const topY = padTop + offsetY + (halfH - finalH) / 2
ctx.drawImage(img, topX, topY, finalW, finalH)
ctx.save()
ctx.translate(0, padTop + bodyH)
ctx.scale(1, -1)
ctx.drawImage(img, topX, (halfH - finalH) / 2 - offsetY, finalW, finalH)
ctx.restore()
} else {
// 退化
const big = Math.round(h * 0.25)
@@ -313,21 +328,57 @@ async function drawJokerBody(ctx, w, h, which, design, project) {
ctx.restore()
}
function drawBackSide(ctx, w, h, design) {
async function drawBackSide(ctx, w, h, design, project) {
ctx.fillStyle = design.background_color || '#1A237E'
ctx.fillRect(0, 0, w, h)
ctx.save()
ctx.strokeStyle = design.border_color || '#FFFFFF'
ctx.lineWidth = 6
const m = w * 0.06
drawRoundedRect(ctx, m, m, w - 2 * m, h - 2 * m, 16)
ctx.stroke()
ctx.fillStyle = design.border_color || '#FFFFFF'
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
ctx.font = `bold ${Math.round(w * 0.1)}px ${design.font_family || 'Times New Roman'}, serif`
ctx.fillText('CARD BACK', w / 2, h / 2)
ctx.restore()
const padX = Math.round(w * 0.15)
const padTop = Math.round(h * 0.18)
const padBot = Math.round(h * 0.22)
const bodyW = w - 2 * padX
const bodyH = h - padTop - padBot
const imageDx = Number(design.image_dx) || 0
const imageDy = Number(design.image_dy) || 0
const imageScale = Number(design.image_scale) || 1
const offsetX = bodyW * imageDx
const offsetY = bodyH * imageDy
const asset = assetByType(project, 'back', 'back')
let img = null
if (asset?.file_url) {
img = imageCache.get(asset.file_url) || null
if (img) await loadImage(asset.file_url)
}
if (img && img.complete && img.naturalWidth) {
const ratio = img.naturalWidth / img.naturalHeight
const target = bodyW / bodyH
let drawW, drawH
if (ratio > target) {
drawW = bodyW; drawH = bodyW / ratio
} else {
drawH = bodyH; drawW = bodyH * ratio
}
const finalW = Math.max(1, drawW * imageScale)
const finalH = Math.max(1, drawH * imageScale)
const drawX = padX + offsetX + (bodyW - finalW) / 2
const drawY = padTop + offsetY + (bodyH - finalH) / 2
ctx.drawImage(img, drawX, drawY, finalW, finalH)
} else {
ctx.save()
ctx.strokeStyle = design.border_color || '#FFFFFF'
ctx.lineWidth = 6
const m = w * 0.06
drawRoundedRect(ctx, m, m, w - 2 * m, h - 2 * m, 16)
ctx.stroke()
ctx.fillStyle = design.border_color || '#FFFFFF'
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
ctx.font = `bold ${Math.round(w * 0.1)}px ${design.font_family || 'Times New Roman'}, serif`
ctx.fillText('CARD BACK', w / 2, h / 2)
ctx.restore()
}
}
/* ---------- 公开 API ---------- */
@@ -365,7 +416,7 @@ export async function renderCard(canvas, project, cardKey) {
await drawJokerBody(ctx, w, h, which, design, project)
drawBorder(ctx, w, h, design)
} else if (cardKey === 'back') {
drawBackSide(ctx, w, h, design)
await drawBackSide(ctx, w, h, design, project)
} else {
const [suit, rank] = cardKey.split('-')
drawBackground(ctx, w, h, design)