모바일 웹 환경에서 이미지 프레임 캡쳐가 제대로 되지 않는 이슈 발생
이미지 사이즈 & 비율 확인
카드 이미지는 360x480px이고, 다운로드 된 이미지는 1240x1920px이리 비율 상으로는 동일한 상태
이미지 css 속성 확인
개발자모드를 켜고 확인을 해보니 화면 속 이미지는 object-fit : cover
인데, 다운로드 된 이미지는 아무 속성이 적용되지 않은 상태로 저장된다는 것을 파악
초기에 html2canvas를 사용하고 있었는데, 해당 라이브러리가 object-fit 속성을 지원하지 않아 생긴 문제라는 것을 파악하고 이미지 프레임 캡쳐에 주로 사용되는 라이브러리를 찾아 비교 분석해봤다.
https://npm-compare.com/dom-to-image,html-to-image,html2canvas
옵션 1
: html2canvas 사용하되object-fit : cover
을 대신한 css 속성 부여옵션 2
: dom-to-image 사용해 toSvg → toPng로 변환
사용하기 더 간단하고 라이브러리 생태계가 큰 html2canvas 사용하되, css 속성 다른 방식으로 해결
// src > hooks > useImageShareDownload.ts
import { saveAs } from 'file-saver';
import html2canvas from 'html2canvas';
const HTML2CANVAS_OPTIONS = {
scale: 4, // 이미지 품질 조절
backgroundColor: null, // "transparent" 속성과 동일
logging: false, // 성능을 위해 로깅 비활성화
useCORS: true, // 외부 이미지 리소스 처리를 위해 필요할 수 있음
allowTaint: false, // 보안을 위해 false로 유지
};
// 이미지 생성
const generateImage = useCallback(async (element: HTMLDivElement): Promise<Blob> => {
try {
// 먼저 캔버스로 이미지 생성
const canvas = await html2canvas(element, HTML2CANVAS_OPTIONS);
// file-saver로 저장하기 위해 Blob으로 변환
return new Promise<Blob>((resolve, reject) => {
canvas.toBlob(
(blob) => {
if (blob) {
resolve(blob);
} else {
reject(new Error('Failed to create blob from canvas'));
}
},
'image/png',
1.0,
);
});
} catch (error) {
console.error('Error in generating image:', error);
throw error;
}
}, []);
// file-saver로 이미지 다운로드
const downloadImage = async (dataUrl: string, fileName: string) => {
try {
const response = await fetch(dataUrl);
const blob = await response.blob();
saveAs(blob, fileName);
showToast('Image downloaded successfully', 'success');
return true;
} catch (error) {
console.error('Download failed:', error);
return false;
}
};
// src > components > molecules > ShareCard.tsx
const ShareCard = ({ backgroundImage, brand, productName, containerRef }: ShareCardProps) => {
return (
<div className="shadow-share-card rounded-[20px]"> // 이미지 저장 시 그림자 제외시키기 위해 분리
<div
ref={containerRef}
className="share-card relative w-[18.125rem] h-[26.25rem] h-min-w-72 min-h-[26.25rem] flex flex-col items-center rounded-[1.25rem] overflow-hidden"
style={{ backgroundColor: 'transparent' }} // tailwind로 동일 속성 적용 안 되기 때문에 인라인 적용
>
<div className="relative w-full h-full flex justify-center items-center overflow-hidden">
{backgroundImage ? (
<Image
src={backgroundImage}
alt="Virtual try-on background"
width={290}
height={420}
style={{
maxWidth: '100%', // 부모 컨테이너 사이즈에
height: 'auto',
}}
priority
quality={100}
loading="eager" // 페이지 로드 시점에 이미지 즉시 로드
crossOrigin="anonymous" // iOS Safari 환경 로드 문제 방지
/>
) : null}
</div>
<div className="absolute inset-0 z-10 flex flex-col items-center w-full h-full mt-[2.494rem] text-center">
{brand ? (
<div className="relative w-[7.5rem] h-10 aspect-auto max-w-[7.5rem] mb-2 overflow-hidden">
<BrandLogo brand={brand} width="100%" height="100%" className="w-full h-full" />
</div>
) : null}
{productName ? <span className="text-body3-paragraph">{productName}</span> : null}
</div>
</div>
</div>
);
};
이미지 품질을 조절하는 scale 옵션을 높이더라도, 어느 정도 이상부터는 다운로드 되는 이미지 품질에 직접적인 영향을 미치지 않고 특정 품질에 머물러 있음.
더 좋은 품질로 올리고 싶은데, 어떤 방법을 사용할 수 있을지?