리팩토링한 이미지 리사이징 로직 또팩토링하기

이예빈·2023년 2월 3일
0
post-thumbnail

프로젝트에 이미지 리사이징 로직을 추가하면서, 그리고 리팩토링하면서 계속 거슬렸던 점이 하나 있다.

코드 중간중간에 그어진 취소선....

대충 레거시니까 안쓰는게 낫다는 뜻...

시간에 쫓기다 보니 급해서 구글링으로 대충 긁어 왔던 코드여서
이해도 잘 안갔었는데 이참에 다시 리팩토링을 해보려고 했다.

기존의 로직에서는 canvas 객체에서 이미지를 리사이징한 후 dataURL로 변환하여 그 URL을 다시 blob으로 변환해주는 작업이 이루어졌다.

canvas에서 blob으로 바로 변환할 수 없을까 하고 찾아보니 바로 나오는 toBlob 메서드...ㅎㅎ

canvas객체에서 바로 blob을 뽑아낼 수 있으므로 url로 변환하고 url을 blob으로 변환하는 불필요한 함수를 제거해버릴 수 있다.

역시 구글은 신이지만 모든 것을 다 수용하면 안된다..

그래서 바로 적용해 보았다.

const resizeImage = (imgEl: HTMLImageElement, fileSize: number) => {
	const canvas = document.createElement('canvas');
	const ratio = Math.sqrt(fileSize / COMP_SIZE);
	let width = Math.ceil((imgEl.width /= ratio));
	let height = Math.ceil((imgEl.height /= ratio));
	canvas.width = width;
	canvas.height = height;
	canvas.getContext('2d')?.drawImage(imgEl, 0, 0, width, height);
 // return canvas.toDataURL('image/jpeg'); ⬅️ 기존 코드
	return canvas;
};

const resizeImageToBlob: (file: File) => Promise<Blob> = file => {
	return new Promise(async resolve => {
		const result = await dataUrlFromFormFile(file);
		const imgEl = document.createElement('img');
		imgEl.onload = () => {
			if (file.size < MAX_SIZE) {
				resolve(file);
			} else {
				const resizedDataUrl = resizeImage(imgEl, file.size);
             // resolve(dataURLtoBlob(resizedDataUrl)); ⬅️ 기존 코드
				resizedDataUrl.toBlob(blob => blob && resolve(blob));
			}
		};
		imgEl.src = result as string;
	});
};

이 것이 toDataUrl로 이중 작업했을 때

이 것이 toBlob으로 간단히 작업했을 ㄸ...어?

이미지의 크기는 줄었지만 용량이 오히려 기존 파일보다 늘어났다.ㅠㅠ
왜지?

toBlob 메서드를 좀더 알아보니 답이 나왔다..

toBlob(callback, type)

toBlob 메서드는 변환할 이미지의 타입(확장자)을 지정해줄 수 있다.
그런데 타입을 지정하지 않는다면 default는 'image/png'로 설정된다.

기존에 url을 blob으로 저장했던 코드를 다시 보면

const resizeImage = (imgEl: HTMLImageElement, fileSize: number) => {
	const canvas = document.createElement('canvas');
	const ratio = Math.sqrt(fileSize / COMP_SIZE);
	let width = Math.ceil((imgEl.width /= ratio));
	let height = Math.ceil((imgEl.height /= ratio));
	canvas.width = width;
	canvas.height = height;
	canvas.getContext('2d')?.drawImage(imgEl, 0, 0, width, height);
	return canvas.toDataURL('image/jpeg');
};

canvas객체에서 URL을 뽑아낼 때 'image/jpeg'로 지정했던 것을 볼 수 있었다.

그래서 blob타입을 다시 jpeg로 지정해보았다.

resizedDataUrl.toBlob(blob => blob && resolve(blob), 'image/jpeg');

기존에 했던 방식과 똑같이 166kb로 제대로 압축이 되었다!

그런데 이미지에 jpeg가 가장 작은 것은 아니다.
webp로 저장하면 용량이 더 줄지 않을까?

resizedDataUrl.toBlob(blob => blob && resolve(blob), 'image/webp');

와..!

43.9KB까지 이미지 사이즈를 줄일 수 있었다!

이제 취소선 없이 코드가 좀더 깔끔해졌다.

profile
temporary potato

0개의 댓글