hookehuyr

fix(SharePoster): 严格裁剪封面图避免溢出到信息区

修改封面图裁剪逻辑,根据源图与目标区域的纵横比选择水平或垂直裁剪
添加封面区域样式限制,防止内容溢出
......@@ -365,15 +365,35 @@ async function compose_poster() {
rounded_rect_path(ctx, card_x, card_y, card_w, card_h, card_radius)
ctx.clip()
// 封面图(对象填充
// 封面图(严格裁剪到封面区域,避免溢出到信息区
const cover_img = await load_image(cover_src.value)
if (cover_img) {
const scale = Math.max(card_w / cover_img.width, cover_h / cover_img.height)
const dw = cover_img.width * scale
const dh = cover_img.height * scale
const dx = card_x + (card_w - dw) / 2
const dy = card_y + (cover_h - dh) / 2
ctx.drawImage(cover_img, dx, dy, dw, dh)
const sw = cover_img.width
const sh = cover_img.height
const dest_ar = card_w / cover_h
const src_ar = sw / sh
let sx = 0, sy = 0, s_w = sw, s_h = sh
// 根据源图与目标区域的纵横比,选择水平或垂直裁剪
if (src_ar > dest_ar) {
// 源图更宽:水平裁剪
s_h = sh
s_w = Math.round(sh * dest_ar)
sx = Math.round((sw - s_w) / 2)
sy = 0
} else {
// 源图更窄或更高:垂直裁剪
s_w = sw
s_h = Math.round(sw / dest_ar)
sx = 0
sy = Math.round((sh - s_h) / 2)
}
// 目标区域严格限定在封面矩形
ctx.save()
ctx.beginPath()
ctx.rect(card_x, card_y, card_w, cover_h)
ctx.clip()
ctx.drawImage(cover_img, sx, sy, s_w, s_h, card_x, card_y, card_w, cover_h)
ctx.restore()
} else {
ctx.fillStyle = '#f3f4f6' // gray-100
ctx.fillRect(card_x, card_y, card_w, cover_h)
......@@ -490,6 +510,12 @@ watch(() => [props.course, props.qr_url], () => {
object-fit: contain;
display: block;
}
.PosterCover {
// 固定封面高度为卡片宽度的 2/3,避免溢出到信息区
aspect-ratio: 3 / 2;
width: 100%;
overflow: hidden;
}
.PosterInfo {
overflow: hidden;
.PosterQR {
......