개발

html2canvas는 어떻게 캔버스를 그릴까

동고킴 2022. 9. 18. 07:35
반응형

html2canvas는 어떻게 화면을 캡처하는지 코드를 통해 알아보자


html2canvas는 자바스크립트로 화면을 캡처할 때 많이 사용되는 오픈소스이다. 깃헙에 어떻게 동작하는지 아래처럼 나와있다.

 

 

DOM과 스타일을 적용하여 캔버스 이미지로 그린다고 되어있다. 실제 사용법도 간단하다. 캡처 대상 element와 옵션만 설정하면 promise로 캔버스를 반환한다. jspdf 라이브러리를 통해 화면을 통째로 PDF로 내보낼 때도 이 오픈소스를 이용하기도 한다. (참고. 자바스크립트로 PDF 내보내기) html2canvas는 어떻게 element를 캔버스로 만들고 있는지 코드를 살펴보았다.  코드는 v1.4.1 기준이다.

 

 

1) 디버깅 모드

기본적으로 logging 옵션(default : true)을 지원한다. 하지만 이 옵션으로는 자세한 디버깅이 힘들다. 하지만 debugger.ts 파일에서 attribute를 통해 디버깅을 할 수 있다는 걸 알 수 있었다. 다양한 디버깅 모드를 지원하는데 목적에 맞게 attribute를 설정하여 디버깅을 할 수 있다.

 



2) renderer

index.ts 파일의 renderElement 함수를 보면 foreignObjectRedering(default : false) 옵션에 따라 render 방식이 달라지는 걸 볼 수 있다. 기본은 각 노드들을 파싱 해서 캔버스에 직접 그리는 방식이고, foreignObjectRedering 방식은 foreignObject를 통해 SVG로 캔버스를 그리는 방식이다.

 

 

 

3) node 파싱 모드 (default)

node 파싱 모드는 CanvasRenderer를 사용한다. node 파싱 모드는 element 타입에 따라 분기 처리되고 있지만, 코드를 따라가 보면 모두 fillRect, fillText, drawImage 등 캔버스 API를 사용하여 캔버스를 그리고 있다.

 

텍스트와 이미지 여부에 따라서 각각 다른 render 함수를 호출하는 부분이다. 코드 아래에는 canvas, ifame, input 등 다양한 if문이 더 존재한다. 텍스트와 이미지 렌더 코드를 살펴보자.

 

 

텍스트 렌더 부분 코드를 살펴보면 fillText, strokeText를 사용하여 캔버스에 텍스트를 그리고 있는 걸 볼 수 있다. 

 

 

renderReplacedElement는 이미지를 캔버스로 그리는 함수이다. image element 뿐만 아니라 canvas, svg element 모두 이 함수를 사용하여 처리하고 있다.

 

 

4) SVG 모드 (foreignObjectRendering : true)

SVG 모드는 ForeignObjectRenderer를 사용한다. foreignObject는 다른 네임스페이스의 요소를 포함한다. SVG를 사용하면 SVG 콘텐츠가 있는 모든 위치에서 외부 네임스페이스의 요소를 포함할  있다. 일반적으로 SVG는 DOM   없는 요소를 포함하지만,   없는 요소를 무시한다. 그렇게 때문에 네임스페이스를 포함하는 foreignObject를 사용하여 SVG를 그리는 것이다.

 

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

const data = `
  <svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
    <foreignObject width="100%" height="100%">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <div style="font-size:40px">Hello world</div>
      </div>
    </foreignObject>
  </svg>
`;

const domUrl = window.URL || window.webkitURL || window;

const img = new Image();
const svg = new Blob([data], { type: "image/svg+xml;charset=utf-8" });
const url = domUrl.createObjectURL(svg);

img.onload = () => {
  ctx.drawImage(img, 0, 0);
  domUrl.revokeObjectURL(url);
};
img.src = url;

 

위 코드는 "Hello world" 텍스트를 foreignObject를 사용하여 svg에 넣은 후 다시 캔버스로 그리는 예제이다. html2canvas도 비슷하게 동작한다. 아래는 html2canvas 코드이다.

 

svg와 foreignObject element를 동적으로 만들고 노드를 foreignObject에 바인딩한다. 그리고 loadSerializedSVG 함수에서 svg 노드를 XMLSerializer로 직렬화 및 인코딩하여 이미지가 로드되면 반환한다.


반응형