142 lines
4.2 KiB
JavaScript
142 lines
4.2 KiB
JavaScript
/**
|
||
* 在照片左下角叠加多行水印文字
|
||
* @param {string} imagePath - 原始图片路径
|
||
* @param {string|string[]} lines - 水印文字,字符串或字符串数组
|
||
* @param {object} [canvasCtx] - APP端传入 { canvasId, proxy, setSize }
|
||
* @returns {Promise<string>} 带水印的图片路径,失败时返回原图
|
||
*/
|
||
export function addWatermark(imagePath, lines, canvasCtx) {
|
||
if (typeof lines === 'string') {
|
||
lines = [lines]
|
||
}
|
||
|
||
return new Promise((resolve) => {
|
||
// 超时保护:10秒
|
||
const timer = setTimeout(() => {
|
||
console.warn('[watermark] timeout')
|
||
resolve(imagePath)
|
||
}, 10000)
|
||
|
||
_doWatermark(imagePath, lines, canvasCtx)
|
||
.then((r) => { clearTimeout(timer); resolve(r || imagePath) })
|
||
.catch((e) => { clearTimeout(timer); console.warn('[watermark]', e); resolve(imagePath) })
|
||
})
|
||
}
|
||
|
||
function _doWatermark(imagePath, lines, canvasCtx) {
|
||
// #ifdef H5
|
||
return _h5(imagePath, lines)
|
||
// #endif
|
||
// #ifdef APP-PLUS
|
||
return _app(imagePath, lines, canvasCtx)
|
||
// #endif
|
||
// eslint-disable-next-line no-unreachable
|
||
return Promise.resolve(imagePath)
|
||
}
|
||
|
||
// ========== H5 ==========
|
||
// #ifdef H5
|
||
function _h5(imagePath, lines) {
|
||
return new Promise((resolve, reject) => {
|
||
const img = new Image()
|
||
img.crossOrigin = 'anonymous'
|
||
img.onload = () => {
|
||
try {
|
||
const w = img.naturalWidth, h = img.naturalHeight
|
||
const c = document.createElement('canvas')
|
||
c.width = w; c.height = h
|
||
const ctx = c.getContext('2d')
|
||
ctx.drawImage(img, 0, 0, w, h)
|
||
_stamp(ctx, w, h, lines, false)
|
||
resolve(c.toDataURL('image/jpeg', 0.9))
|
||
} catch (e) { reject(e) }
|
||
}
|
||
img.onerror = reject
|
||
img.src = imagePath
|
||
})
|
||
}
|
||
// #endif
|
||
|
||
// ========== APP ==========
|
||
// #ifdef APP-PLUS
|
||
function _app(imagePath, lines, cc) {
|
||
if (!cc || !cc.canvasId || !cc.proxy) {
|
||
return Promise.reject(new Error('missing canvasCtx'))
|
||
}
|
||
return new Promise((resolve, reject) => {
|
||
uni.getImageInfo({
|
||
src: imagePath,
|
||
success(info) {
|
||
try {
|
||
// 限制 canvas 宽度 ≤ 1200,避免内存问题
|
||
let dw = info.width, dh = info.height
|
||
if (dw > 1200) { const r = 1200 / dw; dw = 1200; dh = Math.round(info.height * r) }
|
||
|
||
// 更新页面 canvas 尺寸
|
||
if (typeof cc.setSize === 'function') cc.setSize(dw, dh)
|
||
|
||
// 等 DOM 刷新(200ms 足够 APP webview 更新)
|
||
setTimeout(() => {
|
||
try {
|
||
const ctx = uni.createCanvasContext(cc.canvasId, cc.proxy)
|
||
ctx.drawImage(imagePath, 0, 0, dw, dh)
|
||
_stamp(ctx, dw, dh, lines, true)
|
||
|
||
let done = false
|
||
const exp = () => {
|
||
if (done) return
|
||
done = true
|
||
uni.canvasToTempFilePath({
|
||
canvasId: cc.canvasId,
|
||
x: 0, y: 0, width: dw, height: dh,
|
||
destWidth: info.width, destHeight: info.height,
|
||
fileType: 'jpg', quality: 0.9,
|
||
success: (r) => resolve(r.tempFilePath),
|
||
fail: reject
|
||
}, cc.proxy)
|
||
}
|
||
|
||
ctx.draw(false, () => setTimeout(exp, 200))
|
||
// 兜底
|
||
setTimeout(exp, 1200)
|
||
} catch (e) { reject(e) }
|
||
}, 200)
|
||
} catch (e) { reject(e) }
|
||
},
|
||
fail: reject
|
||
})
|
||
})
|
||
}
|
||
// #endif
|
||
|
||
/**
|
||
* 在 canvas context 上绘制水印条
|
||
* @param {boolean} isUni - true 用 uni canvas API,false 用 H5 canvas API
|
||
*/
|
||
function _stamp(ctx, w, h, lines, isUni) {
|
||
const fs = Math.max(Math.floor(w * 0.03), 14)
|
||
const pad = Math.floor(fs * 0.8)
|
||
const lh = fs + pad
|
||
const bgH = lh * lines.length + pad
|
||
|
||
if (isUni) {
|
||
ctx.setFillStyle('rgba(0,0,0,0.4)')
|
||
ctx.fillRect(0, h - bgH, w, bgH)
|
||
ctx.setFillStyle('#ffffff')
|
||
ctx.setFontSize(fs)
|
||
lines.forEach((t, i) => {
|
||
// uni canvas 的 fillText y 是文字顶部基线
|
||
ctx.fillText(t, pad, h - bgH + pad + lh * i)
|
||
})
|
||
} else {
|
||
ctx.fillStyle = 'rgba(0,0,0,0.4)'
|
||
ctx.fillRect(0, h - bgH, w, bgH)
|
||
ctx.fillStyle = '#ffffff'
|
||
ctx.font = `${fs}px sans-serif`
|
||
ctx.textBaseline = 'middle'
|
||
lines.forEach((t, i) => {
|
||
ctx.fillText(t, pad, h - bgH + pad / 2 + lh * i + fs / 2)
|
||
})
|
||
}
|
||
}
|