Skip to content

DOM을 이미지로 저장하기

juhyojeong edited this page Aug 4, 2024 · 1 revision

✏️ 구현하고 싶었던 것

casper-주캐스퍼

캐스퍼 봇 카드 컴포넌트를 이미지로 저장하는 로직을 구현해야했다. 그래서 DOM을 이미지로 저장하는 라이브러리들을 찾아보았다.

1. html2canvas 라이브러리

HTML 요소를 캔버스로 렌더링하고 이미지로 변환할 수 있게 해준다

import React, { useRef } from 'react';
import html2canvas from 'html2canvas';

const App = () => {
  const componentRef = useRef(null);

  const handleSaveImage = () => {
    if (componentRef.current) {
      html2canvas(componentRef.current).then((canvas) => {
        const link = document.createElement('a');
        link.download = 'component.png';
        link.href = canvas.toDataURL();
        link.click();
      });
    }
  };
  
  return (
    <div>
      <div ref={componentRef} className="component-to-save">
        <h1>This is the component to save as an image</h1>
      </div>
      <button onClick={handleSaveImage}>Save as Image</button>
    </div>
  );

}

2. dom-to-image

DOM 요소를 이미지로 변환하는 라이브러리이다.

import React, { useRef } from 'react';
import domtoimage from 'dom-to-image';

const App = () => {
  const componentRef = useRef(null);

  const handleSaveImage = () => {
    if (componentRef.current) {
      domtoimage.toPng(componentRef.current)
        .then((dataUrl) => {
          const link = document.createElement('a');
          link.download = 'component.png';
          link.href = dataUrl;
          link.click();
        })
        .catch((error) => {
          console.error('Failed to save image:', error);
        });
    }
  };

  return (
    <div>
      <div ref={componentRef} className="component-to-save">
        <h1>This is the component to save as an image</h1>
      </div>
      <button onClick={handleSaveImage}>Save as Image</button>
    </div>
  );
};

export default App;

html2canvas와 dom-to-image는 내부 동작도 유사했다. DOM을 캔버스에 그리고 캔버스의 이미지 데이터를 toDataURL를 사용해서 데이터 URL로 만든다. 이 데이터 URL을 기반으로 a 링크로 다운로드 할 수 있다.

dom-to-image에서 dataURL을 반환하는 방식)

function draw(domNode, options) {
    return toSvg(domNode, options)
        .then(util.makeImage)
        .then(util.delay(100))
        .then(function (image) {
            var canvas = newCanvas(domNode);
            canvas.getContext('2d').drawImage(image, 0, 0);
            return canvas;
        });

    function newCanvas(domNode) {
        var canvas = document.createElement('canvas');
        canvas.width = options.width || util.width(domNode);
        canvas.height = options.height || util.height(domNode);

        if (options.bgcolor) {
            var ctx = canvas.getContext('2d');
            ctx.fillStyle = options.bgcolor;
            ctx.fillRect(0, 0, canvas.width, canvas.height);
        }

        return canvas;
    }
}

function toPng(node, options) {
    return draw(node, options || {})
        .then(function (canvas) {
            return canvas.toDataURL();
        });
}

API도 매우 유사하고 둘 다 이미지 추출은 잘 되길래 어떤 라이브러리를 사용해도 크게 상관 없겠다 싶었는데, html2canvas(201.9k)보다 dom-to-image(9.8k)가 번들 사이즈가 훨씬 작았기 때문에 dom-to-image 라이브러리를 사용하게 됐다.

📚 학습 정리

🗂️ 멘토링

Clone this wiki locally