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);
});
}