| | |
| | | type: Array, |
| | | default: () => ['png', 'jpg', 'jpeg', 'webp'], |
| | | }, |
| | | watermarkText: { |
| | | type: String, |
| | | default: '', |
| | | }, |
| | | buttonText: { |
| | | type: String, |
| | | default: '上传图片', |
| | |
| | | return true |
| | | } |
| | | |
| | | async function addWatermarkToFile(rawFile) { |
| | | if (!props.watermarkText) { |
| | | return rawFile |
| | | } |
| | | |
| | | const imageUrl = await readFileAsDataURL(rawFile) |
| | | const image = await loadImage(imageUrl) |
| | | const canvas = document.createElement('canvas') |
| | | const ctx = canvas.getContext('2d') |
| | | |
| | | if (!ctx) { |
| | | return rawFile |
| | | } |
| | | |
| | | canvas.width = image.width |
| | | canvas.height = image.height |
| | | ctx.drawImage(image, 0, 0, canvas.width, canvas.height) |
| | | |
| | | const padding = Math.max(16, Math.round(canvas.width * 0.02)) |
| | | const fontSize = Math.max(24, Math.round(canvas.width * 0.03)) |
| | | const lineHeight = Math.round(fontSize * 1.35) |
| | | const lines = String(props.watermarkText).split('\n').filter(Boolean) |
| | | |
| | | ctx.fillStyle = 'rgba(0, 0, 0, 0.32)' |
| | | const blockHeight = lines.length * lineHeight + padding * 2 |
| | | ctx.fillRect(0, canvas.height - blockHeight, canvas.width, blockHeight) |
| | | ctx.fillStyle = 'rgba(255, 255, 255, 0.96)' |
| | | ctx.font = `${fontSize}px sans-serif` |
| | | ctx.textBaseline = 'bottom' |
| | | |
| | | lines.forEach((line, index) => { |
| | | ctx.fillText(line, padding, canvas.height - padding - (lines.length - 1 - index) * lineHeight) |
| | | }) |
| | | |
| | | const mimeType = rawFile.type || 'image/jpeg' |
| | | const blob = await new Promise((resolve) => canvas.toBlob(resolve, mimeType, 0.92)) |
| | | if (!blob) { |
| | | return rawFile |
| | | } |
| | | |
| | | return new File([blob], rawFile.name, { type: mimeType, lastModified: Date.now() }) |
| | | } |
| | | |
| | | function readFileAsDataURL(file) { |
| | | return new Promise((resolve, reject) => { |
| | | const reader = new FileReader() |
| | | reader.onload = () => resolve(reader.result) |
| | | reader.onerror = reject |
| | | reader.readAsDataURL(file) |
| | | }) |
| | | } |
| | | |
| | | function loadImage(src) { |
| | | return new Promise((resolve, reject) => { |
| | | const img = new Image() |
| | | img.onload = () => resolve(img) |
| | | img.onerror = reject |
| | | img.src = src |
| | | }) |
| | | } |
| | | |
| | | function scheduleUpload(uploadFiles) { |
| | | clearTimeout(uploadQueueTimer.value) |
| | | uploadQueueTimer.value = setTimeout(() => { |
| | |
| | | } |
| | | |
| | | const formData = new FormData() |
| | | validFiles.forEach((file) => { |
| | | formData.append(props.uploadFieldName, file.raw) |
| | | }) |
| | | for (const file of validFiles) { |
| | | const uploadFileObj = await addWatermarkToFile(file.raw) |
| | | formData.append(props.uploadFieldName, uploadFileObj) |
| | | } |
| | | |
| | | uploading.value = true |
| | | proxy.$modal.loading('图片上传中,请稍候...') |