/** * 图片处理工具函数 * 用于压缩和切片图片 */ /** * 加载图片文件为HTMLImageElement */ export function loadImage(file: File): Promise { return new Promise((resolve, reject) => { if (typeof window === 'undefined') { reject(new Error('仅在浏览器环境中支持图片处理')) return } const img = window.document.createElement('img') img.onload = () => { URL.revokeObjectURL(img.src) resolve(img) } img.onerror = (err) => { URL.revokeObjectURL(img.src) reject(err) } img.src = URL.createObjectURL(file) }) } /** * 将Canvas转换为File */ export function canvasToFile( canvas: HTMLCanvasElement, origin: File, quality = 0.85, suffix = '' ): Promise { return new Promise((resolve, reject) => { canvas.toBlob( (blob) => { if (!blob) { reject(new Error('图片压缩失败')) return } const baseName = origin.name.replace(/\.[^/.]+$/, '') const ext = '.jpg' const fileName = suffix ? `${baseName}${suffix}${ext}` : `${baseName}${ext}` resolve(new File([blob], fileName, { type: 'image/jpeg' })) }, 'image/jpeg', quality ) }) } /** * 预览图:只做压缩,不切片 */ export async function compressPreviewImage(file: File): Promise { const img = await loadImage(file) const maxWidth = 800 const maxHeight = 2000 let { width, height } = img const ratio = Math.min(maxWidth / width, maxHeight / height, 1) const canvas = document.createElement('canvas') canvas.width = Math.round(width * ratio) canvas.height = Math.round(height * ratio) const ctx = canvas.getContext('2d') if (!ctx) throw new Error('无法获取画布上下文') ctx.drawImage(img, 0, 0, canvas.width, canvas.height) return await canvasToFile(canvas, file, 0.85) } /** * 展示图:压缩 + 切片,高度>1500则按 1500px 一段切 */ export async function compressAndSliceDisplayImage(file: File): Promise { const img = await loadImage(file) const maxWidth = 800 const maxHeight = 2000 let { width, height } = img const ratio = Math.min(maxWidth / width, maxHeight / height, 1) const targetWidth = Math.round(width * ratio) const targetHeight = Math.round(height * ratio) const sliceMaxHeight = 1500 const results: File[] = [] if (targetHeight <= sliceMaxHeight) { const canvas = document.createElement('canvas') canvas.width = targetWidth canvas.height = targetHeight const ctx = canvas.getContext('2d') if (!ctx) throw new Error('无法获取画布上下文') ctx.drawImage(img, 0, 0, targetWidth, targetHeight) const f = await canvasToFile(canvas, file, 0.85) results.push(f) return results } // 需要切片 const sliceCount = Math.ceil(targetHeight / sliceMaxHeight) for (let i = 0; i < sliceCount; i++) { const sliceTop = i * sliceMaxHeight const sliceHeight = Math.min(sliceMaxHeight, targetHeight - sliceTop) const canvas = document.createElement('canvas') canvas.width = targetWidth canvas.height = sliceHeight const ctx = canvas.getContext('2d') if (!ctx) throw new Error('无法获取画布上下文') ctx.drawImage( img, 0, sliceTop / ratio, width, sliceHeight / ratio, 0, 0, targetWidth, sliceHeight ) const f = await canvasToFile(canvas, file, 0.85, `-part${i + 1}`) results.push(f) } return results }