feat: 背面图案支持 + 大小王素材位置微调 + 10号牌pip修复
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user