87 lines
2.5 KiB
JavaScript
87 lines
2.5 KiB
JavaScript
import { clsx } from "clsx";
|
|
import { twMerge } from "tailwind-merge"
|
|
|
|
export function cn(...inputs) {
|
|
return twMerge(clsx(inputs));
|
|
}
|
|
|
|
/**
|
|
* Compresses and resizes an image file on the client side.
|
|
* If the file is not an image (e.g. PDF), it resolves with the original file.
|
|
*
|
|
* @param {File} file - The file to compress.
|
|
* @param {number} maxWidth - Max width of compressed image.
|
|
* @param {number} maxHeight - Max height of compressed image.
|
|
* @param {number} quality - Compression quality between 0 and 1.
|
|
* @returns {Promise<File>} - A promise that resolves to the compressed File object.
|
|
*/
|
|
export function compressImage(file, maxWidth = 1200, maxHeight = 1200, quality = 0.8) {
|
|
return new Promise((resolve) => {
|
|
if (!file || !file.type.startsWith('image/')) {
|
|
resolve(file);
|
|
return;
|
|
}
|
|
|
|
const reader = new FileReader();
|
|
reader.onload = (event) => {
|
|
const img = new Image();
|
|
img.onload = () => {
|
|
let width = img.width;
|
|
let height = img.height;
|
|
|
|
// Calculate aspect ratio
|
|
if (width > height) {
|
|
if (width > maxWidth) {
|
|
height = Math.round((height * maxWidth) / width);
|
|
width = maxWidth;
|
|
}
|
|
} else {
|
|
if (height > maxHeight) {
|
|
width = Math.round((width * maxHeight) / height);
|
|
height = maxHeight;
|
|
}
|
|
}
|
|
|
|
const canvas = document.createElement('canvas');
|
|
canvas.width = width;
|
|
canvas.height = height;
|
|
const ctx = canvas.getContext('2d');
|
|
if (!ctx) {
|
|
resolve(file);
|
|
return;
|
|
}
|
|
|
|
// Draw image
|
|
ctx.drawImage(img, 0, 0, width, height);
|
|
|
|
// Convert to blob
|
|
if (canvas.toBlob) {
|
|
canvas.toBlob(
|
|
(blob) => {
|
|
if (blob) {
|
|
// Keep original extension or use jpeg, but File constructor needs a name
|
|
const compressedFile = new File([blob], file.name.substring(0, file.name.lastIndexOf('.')) + '.jpg', {
|
|
type: 'image/jpeg',
|
|
lastModified: Date.now()
|
|
});
|
|
resolve(compressedFile);
|
|
} else {
|
|
resolve(file);
|
|
}
|
|
},
|
|
'image/jpeg',
|
|
quality
|
|
);
|
|
} else {
|
|
resolve(file);
|
|
}
|
|
};
|
|
img.onerror = () => resolve(file);
|
|
img.src = event.target.result;
|
|
};
|
|
reader.onerror = () => resolve(file);
|
|
reader.readAsDataURL(file);
|
|
});
|
|
}
|
|
|