100 lines
2.8 KiB
TypeScript
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)
|
|
})
|
|
}
|