글 작성 기능을 구현하면서, 첨부된 이미지의 크기가 500kb보다 크면 서버에서 응답을 해주지 못하는 문제가 발생했다. 큰 이미지도 받을 수 있도록 서버 코드를 수정할 수도 있겠지만, 프론트에서 이미지 크기를 줄여서 보내면 서버 비용을 절감할 수 있을 것 같아 구현해보기로 했다.
browser-image-compression은 이미지 압축을 위해 웹 브라우저에서 실행되는 Javascript 모듈이다. 공식 홈페이지에서는 이미지를 서버에 업로드하기 전에 해상도 혹은 크기를 줄여 jpeg, png, webp 및 bmp 이미지를 압축하는 데 이 모듈을 사용할 수 있다고 설명하고 있다.
yarn add browser-image-compression // yarn 사용시
npm install browser-image-compression --save // npm 사용시
import imageCompression from 'browser-image-compression';
imageCompression
모듈은 첫 번째 인자로 이미지 파일을, 두 번째 인자로 옵션을 받는다.
imageCompression(file: File, options: Options): Promise<File>
사용 가능한 옵션 리스트는 아래와 같다.
// maxSizeMB, maxWidthOrHeight 중에서 하나는 반드시 포함해야 한다!
const options: Options = {
maxSizeMB: number,
maxWidthOrHeight: number,
onProgress: Function,
useWebWorker: boolean,
libURL: string,
preserveExif: boolean,
signal: AbortSignal,
maxIteration: number,
exifOrientation: number,
fileType: string,
initialQuality: number,
alwaysKeepResolution: boolean
}
이미지 파일을 인자로 받아 크기가 줄어든 새 파일을 리턴해 주는 함수를 만들어 보자. imageCompression
모듈은 비동기로 동작하니 async await
혹은 .then
을 이용해야 한다.
const getImgUpload = async (image: File) => {
const resizingBlob = await imageCompression(image, { maxSizeMB: 0.5 });
return resizingBlob;
};
원본 파일과 리사이징 파일을 콘솔에 찍어보면 크기가 확연히 줄어든 것을 알 수 있다.
imageCompression
모듈을 이용하면 크기를 줄인 파일을 Blob
형태로 리턴해 준다. 내가 진행하고 있는 프로젝트에서는 File
타입을 사용해야 하므로, 변환 코드를 추가한다. 참고로, File 생성자는 new File(bits, name, options)
와 같은 형태로 사용한다.
const getImgUpload = async (image: File) => {
const resizingBlob = await imageCompression(image, { maxSizeMB: 0.5 });
const resizingFile = new File([resizingBlob], image.name, { type: image.type });
return resizingFile;
};
리사이징 파일이 Blob
에서 File
이 된 것을 확인할 수 있다.
원본 사진의 크기와 maxSizeMB
의 차이가 크다면 이미지 리사이징에 시간이 오래 걸린다. 따라서 사용자에게 혼란을 주지 않으려면 사진이 변환되고 있다는 사실을 적절히 알려줄 수 있는 UI를 적용해야 할 것이다.