import { ElMessage } from 'element-plus'; export interface CompressionLevel { maxWidth: number; maxHeight: number; quality: number; } export const DEFAULT_COMPRESSION_LEVELS: CompressionLevel[] = [ { maxWidth: 800, maxHeight: 800, quality: 0.6 }, { maxWidth: 600, maxHeight: 600, quality: 0.5 }, { maxWidth: 400, maxHeight: 400, quality: 0.4 }, ]; /** * 压缩图片 * @param file - 要压缩的图片文件 * @param maxWidth - 最大宽度 * @param maxHeight - 最大高度 * @param quality - 压缩质量 (0-1) * @returns 压缩后的 Blob */ export function compressImage( file: File, maxWidth = 1024, maxHeight = 1024, quality = 0.8, ): Promise { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (e) => { const img = new Image(); img.onload = () => { const canvas = document.createElement('canvas'); let width = img.width; let height = img.height; if (width > maxWidth || height > maxHeight) { const ratio = Math.min(maxWidth / width, maxHeight / height); width = width * ratio; height = height * ratio; } canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d')!; ctx.drawImage(img, 0, 0, width, height); canvas.toBlob( (blob) => { if (blob) { resolve(blob); } else { reject(new Error('压缩失败')); } }, file.type, quality, ); }; img.onerror = reject; img.src = e.target?.result as string; }; reader.onerror = reject; reader.readAsDataURL(file); }); } /** * 将 Blob 转换为 base64 * @param blob - Blob 对象 * @returns base64 字符串 */ export function blobToBase64(blob: Blob): Promise { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => { resolve(reader.result as string); }; reader.onerror = reject; reader.readAsDataURL(blob); }); } /** * 尝试多级压缩直到满足大小限制 * @param file - 图片文件 * @param currentTotalLength - 当前已使用的总长度 * @param maxTotalLength - 最大允许总长度 * @returns 压缩结果或 null(如果无法满足限制) */ export async function tryCompressToLimit( file: File, currentTotalLength: number, maxTotalLength: number, compressionLevels = DEFAULT_COMPRESSION_LEVELS, ): Promise<{ blob: Blob; base64: string; estimatedLength: number } | null> { for (const level of compressionLevels) { const compressedBlob = await compressImage( file, level.maxWidth, level.maxHeight, level.quality, ); const base64 = await blobToBase64(compressedBlob); const estimatedLength = Math.floor(base64.length * 0.5); if (currentTotalLength + estimatedLength <= maxTotalLength) { return { blob: compressedBlob, base64, estimatedLength }; } } return null; } /** * Composable: 使用图片压缩 */ export function useImageCompression() { return { compressImage, blobToBase64, tryCompressToLimit, DEFAULT_COMPRESSION_LEVELS, }; }