38 lines
1.5 KiB
TypeScript
38 lines
1.5 KiB
TypeScript
/**
|
|
* Уменьшение изображения на клиенте перед загрузкой (canvas → JPEG).
|
|
* Ограничивает большую сторону до `max` px, чтобы не грузить тяжёлые файлы.
|
|
* При любой ошибке возвращает исходный файл — сервер всё равно проверит тип/размер.
|
|
*/
|
|
export async function resizeImage(file: File, max = 1600): Promise<Blob> {
|
|
try {
|
|
const dataUrl = await new Promise<string>((res, rej) => {
|
|
const fr = new FileReader();
|
|
fr.onload = () => res(fr.result as string);
|
|
fr.onerror = () => rej(fr.error);
|
|
fr.readAsDataURL(file);
|
|
});
|
|
const img = await new Promise<HTMLImageElement>((res, rej) => {
|
|
const i = new Image();
|
|
i.onload = () => res(i);
|
|
i.onerror = () => rej(new Error("image load failed"));
|
|
i.src = dataUrl;
|
|
});
|
|
let { width, height } = img;
|
|
if (width > max || height > max) {
|
|
const scale = Math.min(max / width, max / height);
|
|
width = Math.round(width * scale);
|
|
height = Math.round(height * scale);
|
|
}
|
|
const canvas = document.createElement("canvas");
|
|
canvas.width = width;
|
|
canvas.height = height;
|
|
const ctx = canvas.getContext("2d");
|
|
if (!ctx) return file;
|
|
ctx.drawImage(img, 0, 0, width, height);
|
|
const blob = await new Promise<Blob | null>((res) => canvas.toBlob(res, "image/jpeg", 0.85));
|
|
return blob ?? file;
|
|
} catch {
|
|
return file;
|
|
}
|
|
}
|