Last active
October 23, 2023 18:49
-
-
Save enesien/71b43dee4034d86d8ecee61e74649b02 to your computer and use it in GitHub Desktop.
Resize images in any Typescript project within the client, including Capacitor native apps
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface ResizeOptions { | |
/** | |
* Desired width of the image. | |
*/ | |
width: number; | |
/** | |
* Desired height of the image. | |
*/ | |
height: number; | |
/** | |
* A number between 0 and 1 indicating image quality. | |
* | |
* @default 1 | |
*/ | |
quality?: number; | |
/** | |
* If true, will throw an error if a smaller image is passed in | |
* @default false | |
*/ | |
throwOnSmaller?: boolean; | |
} | |
export const resizeImage = async (file: File, options: ResizeOptions): Promise<File> => { | |
return new Promise((resolve, reject) => { | |
if (!file.type.match(/image.*/)) { | |
return reject('Not an image'); | |
} | |
if (file.type.match(/image\/gif/)) { | |
return reject('Cannot resize GIFs'); | |
} | |
const image = document.createElement('img'); | |
image.onload = () => { | |
const canvas = document.createElement('canvas'); | |
const cleanup = () => { | |
image.remove(); | |
canvas.remove(); | |
} | |
canvas.width = options.width; | |
canvas.height = options.height; | |
if (options.throwOnSmaller && (image.width < options.width || image.height < options.height)) { | |
cleanup(); | |
return reject('Image too small'); | |
} | |
const ctx = canvas.getContext('2d'); | |
if (!ctx) { | |
cleanup(); | |
return reject('Could not create canvas context'); | |
} | |
const smallestSide = Math.min(image.width, image.height); | |
const left = (image.width - smallestSide) / 2; | |
const top = (image.height - smallestSide) / 2; | |
ctx.drawImage(image, left, top, smallestSide, smallestSide, 0, 0, ctx.canvas.width, ctx.canvas.height); | |
canvas.toBlob((blob) => { | |
if (!blob) { | |
cleanup() | |
return reject('Could not create canvas blob'); | |
} | |
resolve(new File([blob], file.name, { | |
type: 'image/jpeg', | |
lastModified: Date.now() | |
})); | |
cleanup(); | |
}, file.type, options.quality || 1); | |
}; | |
image.onerror = () => { | |
image.remove(); | |
return reject('Failed to load image'); | |
} | |
const reader = new FileReader(); | |
reader.onerror = (e) => { | |
image.remove(); | |
reject(`Could not read file: ${e.target?.error}`) | |
}; | |
reader.onload = (evt) => { | |
if (!evt.target) { | |
image.remove(); | |
return reject('Could not read file; no target'); | |
} | |
image.src = evt.target.result as string; | |
}; | |
reader.readAsDataURL(file); | |
}) | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Used in our cross-platform mobile apps