@imjano/compress_image
Version:
Compresses an image file while allowing control over quality, file size, and format.
94 lines (91 loc) • 2.92 kB
text/typescript
interface CompressImageOptions {
qualityPercent?: number
maxFileSize?: number
minFileSize?: number
format?:
| 'image/jpeg'
| 'image/png'
| 'image/webp'
| 'image/gif'
| 'image/bmp'
| 'image/tiff'
| 'image/svg+xml'
}
/**
* Compresses an image file while allowing control over quality, file size, and format.
*
* @param file - The File object representing the image to compress.
* @param options - Configuration options for image compression.
* @returns A Promise that resolves to the compressed image as a Blob.
* @example
* // Compress an image with custom options
* const compressionOptions = {
* qualityPercent: 80, // Set compression quality to 80%
* maxFileSize: 1024 * 1024, // Limit the output file size to 1MB
* format: 'image/jpeg', // Convert to JPEG format
* };
* compressImage(imageFile, compressionOptions)
* .then((compressedBlob) => {
* // Handle the compressed image Blob
* })
* .catch((error) => {
* console.error('Compression error:', error);
* });
*/
export default async function compressImage(
file: File,
options: CompressImageOptions
): Promise<Blob> {
const { format } = options
let { qualityPercent, minFileSize, maxFileSize } = options
minFileSize = minFileSize ?? 512
maxFileSize = maxFileSize ?? file.size
qualityPercent = qualityPercent ?? 100
if (!maxFileSize && !qualityPercent)
throw Error('qualityPercent must be a number between 0 and 100')
if (qualityPercent)
if (qualityPercent > 100 || qualityPercent < 0)
throw Error('qualityPercent must be a number between 0 and 100')
let blob = await compression(file, format, qualityPercent)
if (maxFileSize) {
if (maxFileSize > file.size)
throw Error(
`maxFileSize (${maxFileSize}) must not be larger than the original file size (${file.size})`
)
while (blob.size > maxFileSize || blob.size < minFileSize) {
if (blob.size > maxFileSize) {
qualityPercent = qualityPercent -= 10
blob = await compression(file, format, qualityPercent)
} else if (blob.size > minFileSize) {
qualityPercent += 5
blob = await compression(file, format, qualityPercent)
}
}
}
return blob
}
const compression = (
file: File,
format?: string,
qualityPercent?: number
): Promise<Blob> => {
return new Promise((resolve, reject) => {
const canvas = document.createElement('canvas')
const image = new Image()
image.onload = () => {
canvas.width = image.width
canvas.height = image.height
canvas.getContext('2d')?.drawImage(image, 0, 0)
canvas.toBlob(
(blob) => {
URL.revokeObjectURL(image.src)
if (blob) return resolve(blob)
return reject(new Error('Failed to create blob'))
},
format ? format : file.type,
(qualityPercent ?? 100) / 100
)
}
image.src = URL.createObjectURL(file)
})
}