Files
Yi.Admin/Yi.Ai.Vue3/src/composables/chat/useImageCompression.ts

128 lines
3.2 KiB
TypeScript
Raw Normal View History

2026-01-31 23:38:39 +08:00
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<Blob> {
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<string> {
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,
};
}