html-to-image Safari 크로스 브라우징

kim unknown·2025년 7월 10일
0

React

목록 보기
9/9
post-thumbnail

웹페이지를 이미지로 저장하는 기능을 구현하게 되었다. 하지만 언제나 복병인 ios/safari에서 웹페이지 내부에 자리하고 있는 이미지 요소가 누락되어 저장되는 이미지가 발생했고, 이를 해결한 과정을 기록해보려고 한다.

우선 나는 이미지화를 위해 html-to-image 라이브러리를 활용했다.
html-to-image의 동작 방식부터 알아보자.


1. html-to-image 동작 방식

  1. DOM 요소를 SVG 문자열로 직렬화
  2. SVG를 <img>로 만든 후 <canvas>에 그림
  3. 그린 결과물을 다시 toBlob()으로 추출
    👉 이 때, SVG 내부에 들어간 image, font 등이 GPU 레이어에 반영되기 전이면
    빈 그림이 그려지며 이미지가 누락된 캡쳐가 발생

2. 이슈 원인 : Safari 비동기 렌더링

내가 파악한 이슈의 원인은 다음과 같다.

Safari는 html-to-image로 DOM을 캡쳐할 때, 외부 이미지나 blob URL을 렌더링 직전에 비동기로 불러온다.
렌더 타이밍에 따라 이미지가 GPU 레이어에 올라가기 전에 toBlob이 실행될 수 있다.
👉 이로 인해 간헐적으로 canvas에 그림을 못 그리고, 빈 blob이 생성된 채로 캡쳐 이미지가 생성된 것이었다.

💡 Safari는 DOM에 그려진 것처럼 보여도, 내부적으로 GPU 레이어에 실제 이미지나 폰트가 올라오지 않은 상태일 수 있다.

💡 Safari는 리소스 최적화를 위해 백그라운드 탭에서의 이미지 로딩을 지연시키거나, 크로스-오리진 이미지에서 CORS 정책을 더 엄격하게 적용하기도 한다.


3. 해결 방안 : Blob 사이즈를 활용하기

구글링해 본 결과 html-to-image 라이브러리에도 이미 해당 이슈가 등록 되어 있었고, 여러가지 방법을 시도해보았지만 이슈를 해결할 수 있었던 건 Blob 사이즈를 검사하는 방식이었다.

✨ Blob의 사이즈를 확인하여 이미지 요소가 정상적으로 렌더되었는지 확인 후 이미지 저장을 시도하도록 시점을 변경하였다.
⇒ Safari가 GPU 렌더링까지 끝낼 수 있도록 시간을 벌면서 반복 재시도
⇒ 이미지가 완전히 그려진 후 캡쳐됨으로써 이미지 누락 문제 해결


4. 시도한 Safari 대응 방법

방법설명
await document.fonts.ready폰트 렌더 대기 후 완료 확인
await requestAnimationFrame()DOM이 GPU에 올라갈 시간 확보
프로젝트 내부 public 이미지 사용CORS 대응을 위해 외부 이미지 대신 로컬 이미지 사용
pixelRatio는 최대 2로 설정GPU 병목 방지
Blob size 체크 & 반복 재시도이미지 요소 정상 렌더 완료 확인

Summary
Safari가 이미지/폰트 렌더링을 완료하기 전에 캡쳐가 시도되어 이미지가 누락 되는 이슈 발생. 정상적으로 렌더링된 Blob의 사이즈인지 검사 후 캡쳐 시도하도록 개선.



🔥 Image is not showing in some cases iOS, Safari

profile
과거의 나에게 묻기 위한 기록

0개의 댓글