HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
👻
개발 기록
/
🏢
회사 개발 노트
/
왓챠 노트
왓챠 노트
/
🏞️
DOM을 이미지로 완벽하게 저장하는 방법
🏞️

DOM을 이미지로 완벽하게 저장하는 방법

사용한 라이브러리

  • html2canvas
    • canvasElement 반환.
  • htmlToImage
    • base 64 img url 반환.
 
💡
결론 : - 외부 url 링크가 존재하고 ios 대응을 해야 한다면 html2canvas를, - 웹만 대응하는 등 그 외의 경우엔 htmlToImage를 추천함.
 
 

👇 결론에 이르기까지의 과정 👇

 

htmlToImage를 사용한 이유

  • html2canvas에 비해 적은 용량과 제로 디펜던시.
    • notion image
  • CSS가 깨지지 않음.
  • toPng, toJpeg 등 직관적인 사용 방법 (개인적으로 option들도 더 사용하기 쉬웠음).
  • html2canvas보다 최근에 업데이트 됨.
notion image
 

라이브러리에 사용된 문법 정리

💡
dom을 이미지화시킨 핵심 문법에 대해 알아보자.
 
  • HTML <canvas> 태그
    • 주로 자바스크립트와 같은 스크립트를 이용하여 그래픽 콘텐츠를 그릴 때 사용함.
    • src, alt 속성이 없다는 점만 제외하면 img 태그처럼 보임. 실제로 canvas에는 width, height 두 속성만 있음. default 값은 300px * 150px임.
    • <canvas id="myCanvas" style="border: 2px solid black"> 이 문장은 사용자의 웹 브라우저가 canvas 요소를 지원하지 않을 때 나타납니다! </canvas> <script> var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); context.fillStyle = "yellow"; context.fillRect(0,0,150,100); </script>
  • getContext()
    • 캔버스는 처음에 비어있기 때문에 무언가를 표시하기 위해서, 어떤 스크립트가 랜더링 컨텍스트에 접근하여 그리야 함.
    • getContext() 메소드는 캔버스의 드로잉 컨텍스트를 반환함.
    • 파라미터는 contextType을 받음. 2d를 넣었을 때 2차원 렌더링 컨텍스트를 나타내는 CanvasRenderingContext2D 객체를 생성함.
  • drawImage()
    • Canvas 2D API의 drawImage() 메서드는 캔버스에 이미지를 그리는 다양한 방법을 제공함.
    • drawImage(image, dx, dy)
  • toDataURL()
    • 지정된 형식으로 이미지를 나타내는 데이터 URL을 반환함.
    • 원하는 파일 형식과 이미지 품질을 지정할 수 있음.
 

cross platform 대응

 
👇 간단한 프로젝트로 테스트해봄. readme 참고.
 
💡
이미지가 없으면 크게 상관없음. 근데 이미지가 있으면 얘기가 달라짐.
 
Chrome
  • 정상 동작함.
 
Safari
  • htmlToImage를 사용했을 때 2가지 문제가 생김.
    • notion image
      1. 이미지가 나오지 않음.
      1. 폰트 깨짐.
  • 해결 방법 요약
    • toJpeg를 사용하자.
    • 해당 메서드를 두 번 사용하자.
  • 해결 과정
    • 우선 toPng에서 toJpeg로 변경. png는 성격 상 많은 옵션들을 담고 있기에 뭔가 깨지는 게 생기나봄. mdn에도 png를 지원하려면 많은 것들이 필요하다 나와있음.
    • 하지만 jpeg로 저장해도 폰트는 깨지지 않지만 이미지는 여전히 나오지 않음.
    • 한 가지 알아야 할 점이 htmlToImage는 domToImage라는 라이브러리를 근간으로 하는데 domToImage가 사파리 지원을 안함.
    • htmlToImage 깃허브 리드미 발췌.
      htmlToImage 깃허브 리드미 발췌.
    • 이 때 domToImage에서 지원하는 메서드를 두 번 실행하면 이미지가 제대로 렌더링됨.
      • safari 첫 번째 렌더링에서 이미지를 누락시키는 것으로 추정.
      export const quizResultToImage = async ({ target, bgColor = "#000000", }: Props) => { await toJpeg(target, { backgroundColor: bgColor }); // 1 return await toJpeg(target, { backgroundColor: bgColor }); // 2 };
      깔끔한 방법은 아니지만 일단 되니까..
 
사파리에서 성공적으로 저장된 형태
사파리에서 성공적으로 저장된 형태
 
IOS
ios에는 두 가지 문제가 있음.
ipad
ipad
ios
ios
  1. 이미지 안보임 (htmlToImage 동일).
      • 왜 htmlToImage에서 이미지가 보이지 않을까?
      • 아직 미해결인듯 하다..
      • 심지어 아이패드에서는 문제가 없었던 레이아웃까지 말썽부림.
  1. 이미지 저장 시 바로 저장되는 게 아닌 크롬에 저장 후 크롬 저장 페이지에서 별도로 저장해야 함.
      • html을 이미지로 만들어서 팝업창에 띄우고 이를 꾹 눌러 저장시키는 방법으로 대체.
      • ios에서는 다운받은 이미지를 바로 갤러리에 저장하지 못하게 함.
 
⚠️
깃허브 레포에서 나타내는 바와 같이, 결국 htmlToImage는 ios에서 이미지를 렌더링하지 않기 때문에 html2canvas를 이용함. 그리고 깨지는 css에 대해 주먹구구식으로 스타일을 수정함. 맞는 방법일까.. 🤔
 

그 외 에러 )

구글 폰트 사용시 cssRules를 어긋난다는 경고
SecurityError: Failed to read the 'cssRules' property from 'CSSStyleSheet': Cannot access rules
해결
구글 폰트 사용한 link에 crossorigin="anonymous"으로 설정해줘야 함.
<link href="https://fonts.googleapis.com/css?family=Abril+Fatface&display=swap" rel="stylesheet" crossorigin="anonymous">
 

기타 ) 한글로 저장시키면 폰트가 깨지지 않을까?

  • 깨지는 케이스 발견하지 못함.
 
 
 
참고 자료
Here’s Why I’m Replacing html2canvas With html-to-image in Our React App
Lessons Learned from Converting Html to Image