Files
qitongxue-wx/src/utils/image/collage.ts
2026-09-17 14:39:15 +08:00

100 lines
2.8 KiB
TypeScript

/**
* 图片拼图:模板槽位定义 + Canvas 合成
* 槽位坐标为画布百分比;间距/圆角在绘制时按像素换算。
*/
export interface CollageSlot {
x: number // %
y: number // %
w: number // %
h: number // %
}
export interface CollageTemplate {
key: string
name: string
count: number
slots: CollageSlot[]
}
export const COLLAGE_TEMPLATES: CollageTemplate[] = [
{ key: 'h2', name: '左右两张', count: 2, slots: [{ x: 0, y: 0, w: 50, h: 100 }, { x: 50, y: 0, w: 50, h: 100 }] },
{ key: 'v2', name: '上下两张', count: 2, slots: [{ x: 0, y: 0, w: 100, h: 50 }, { x: 0, y: 50, w: 100, h: 50 }] },
{
key: 'l1r2',
name: '左大右二',
count: 3,
slots: [{ x: 0, y: 0, w: 58, h: 100 }, { x: 58, y: 0, w: 42, h: 50 }, { x: 58, y: 50, w: 42, h: 50 }],
},
{ key: 'h3', name: '三竖条', count: 3, slots: [{ x: 0, y: 0, w: 33.34, h: 100 }, { x: 33.34, y: 0, w: 33.33, h: 100 }, { x: 66.67, y: 0, w: 33.33, h: 100 }] },
{
key: 'grid4',
name: '四宫格',
count: 4,
slots: [{ x: 0, y: 0, w: 50, h: 50 }, { x: 50, y: 0, w: 50, h: 50 }, { x: 0, y: 50, w: 50, h: 50 }, { x: 50, y: 50, w: 50, h: 50 }],
},
{
key: 't1b3',
name: '上大下三',
count: 4,
slots: [{ x: 0, y: 0, w: 100, h: 52 }, { x: 0, y: 52, w: 33.34, h: 48 }, { x: 33.34, y: 52, w: 33.33, h: 48 }, { x: 66.67, y: 52, w: 33.33, h: 48 }],
},
]
/** 单槽位圆角矩形 clip + cover 绘制 */
function drawSlot(
ctx: CanvasRenderingContext2D,
slot: CollageSlot,
size: number,
img: unknown,
imgW: number,
imgH: number,
gap: number,
radius: number,
) {
const sx = (slot.x / 100) * size + gap / 2
const sy = (slot.y / 100) * size + gap / 2
const sw = (slot.w / 100) * size - gap
const sh = (slot.h / 100) * size - gap
if (sw <= 0 || sh <= 0)
return
const scale = Math.max(sw / imgW, sh / imgH)
const dw = imgW * scale
const dh = imgH * scale
const dx = sx + (sw - dw) / 2
const dy = sy + (sh - dh) / 2
ctx.save()
const rr = Math.min(radius, sw / 2, sh / 2)
ctx.beginPath()
ctx.moveTo(sx + rr, sy)
ctx.arcTo(sx + sw, sy, sx + sw, sy + sh, rr)
ctx.arcTo(sx + sw, sy + sh, sx, sy + sh, rr)
ctx.arcTo(sx, sy + sh, sx, sy, rr)
ctx.arcTo(sx, sy, sx + sw, sy, rr)
ctx.closePath()
ctx.clip()
ctx.drawImage(img as CanvasImageSource, dx, dy, dw, dh)
ctx.restore()
}
/** 合成整张拼图 */
export function drawCollage(
ctx: CanvasRenderingContext2D,
size: number,
tpl: CollageTemplate,
loaded: Array<{ img: unknown, width: number, height: number }>,
gap: number,
radius: number,
bg: string,
) {
ctx.save()
ctx.fillStyle = bg
ctx.fillRect(0, 0, size, size)
ctx.restore()
loaded.forEach((item, i) => {
const slot = tpl.slots[i]
if (slot)
drawSlot(ctx, slot, size, item.img, item.width, item.height, gap, radius)
})
}