Next/Image는 크게 로컬 이미지(정적 이미지)와 리모트 이미지(다이나믹 이미지)로 나뉜다. /public
폴더에 저장한 로컬 이미지는 빌드 타임에 import한 이미지 파일의 width
height
를 자동으로 지정하고 [base64로 인코딩한 이미지가 생성](https://nextjs.org/docs/api-reference/next/image#:~:text=If src is an object from a static import and the imported image is .jpg%2C .png%2C .webp%2C or .avif%2C then blurDataURL will be automatically populated.)된다. 따라서 추가 작업 없이 블러 처리된 Placeholder를 사용할 수 있다.
<Image
src="/me.png"
alt="Picture of the author"
placeholder="blur"
// width={500} automatically provided
// height={500} automatically provided
// blurDataURL="data:..." automatically provided
/>
그 외 상황은 리모트 이미지로 구분한다. 이때 블러 처리된 Placeholder를 사용하려면 plaiceholder 같은 라이브러리를 사용하거나 캔버스 API를 이용해서 4×4 정도의 사이즈(보통 300바이트 미만)로 줄인 후 base64로 변환하는 작업이 필요하다. NextJS 공식 문서에선 10 픽셀 미만의 사이즈를 권장하고 있다.
사용자 컴퓨터에서 이미지를 선택한 후 업로드한 경우엔 유틸 함수를 만들어서 사용할 수 있다. 이미지 크롭 등의 상황에서 사용하면 유용하다. ❶로컬 컴퓨터에서 이미지 선택 ➋이미지 크롭 ➌Placeholder로 사용할 base64 문자열을 생성하고, 크롭 이미지 원본은 서버로 전송 ❹크롭 이미지 렌더.
export const toDataURL = (
img: HTMLImageElement,
width: number,
height: number
) => {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
if (!ctx) throw new Error("No 2d context");
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0, width, height);
// 1번째 인자 : HTMLImageElement, SVGImageElement 등 이미지 소스 엘리먼트
// 2번째 인자(dx) : 캔버스에 그릴 x축 좌표
// 3번째 인자(dy) : 캔버스에 그릴 y축 좌표
// 4번째 인자(dw) : 캔버스에 그릴 width
// 5번재 인자(dy) : 캔버스에 그릴 height
return canvas.toDataURL(); // 리사이즈한 이미지를 base64(data URL) 문자열로 변환
};
// 이미지 엘리먼트를 받아 4×4로 리사이즈한 base64 문자열을 반환하는 함수
export const getBlurDataURL = (img: HTMLImageElement) => {
return toDataURL(img, 4, 4);
};
<aside> 💡 URL.createObjectURL 대신 FileReader API를 사용할 수도 있다(참고 노트)
</aside>
// <input type="file" ... /> 엘리먼트의 onChange 핸들러
const image = e.target.files?.[0];
if (image) {
const blobUrl = URL.createObjectURL(image);
const img = new Image();
img.src = blobUrl;
img.onload = () => {
const base64 = getBlurDataURL(img); // "data:image/png;base64,iVBw...
URL.revokeObjectURL(blobUrl); // 이미지 로드를 완료하면 메모리 누수 방지를 위해 폐기
// ...원하는 작업 수행
// base64 문자열은 Next/Image의 blurDataURL 속성에 사용한다
};
}
4×4로 리사이즈한 이미지. 평균적으로 200바이트 미만의 용량으로 줄어든다
<aside> 💡 TailwindCSS 유틸리티 클래스 형태로 사용할 수 있는 @plaiceholder/tailwindcss 플러그인도 있다
</aside>
plaiceholder 라이브러리는 LQIP(저화질 이미지) 생성을 도와주는 NodeJS 라이브러리다. Base64, SVG 등 포맷으로 생성할 수 있다. Next/Image의 blurDataURL
속성에 사용하려면 Base64로 생성하면 된다. 공식 문서에 따르면 Base64 포맷은 일반적으로 ~300 Bytes 미만 사이즈로 생성된다고 한다.