๐ ๋ค์ด๊ฐ๋ฉฐ
React์์ ํ๋ฉด (DOM)๋ฅผ ์บก์ฒ, ์ ์ฅํ๋ ๊ธฐ๋ฅ์ ๋ํด์ ์์๋ณด๋ ค ํฉ๋๋ค.
์์ ํ ์ด ํ๋ก์ ํธ๋ฅผ ํ๋ฉด์ ์ฌ๋ฌ๊ฐ์ง ๋ฌธ์ ๋ฅผ ๋ง์ด ํ์๋๋ฐ, ๊ฒฐ๊ณผ์ ์ผ๋ก ์ฑ๊ณตํ ๋ฐฉ๋ฒ๋ค๋ก ํฌ์คํ ํ๊ฒ ๋ฉ๋๋ค.
์บก์ณ(์คํฌ๋ฆฐ์ท)์ ๋์์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค
๋ํ์ ์ผ๋ก html2canvas, dom-to-image, html-to-image ๋ฑ์ด ์์ต๋๋ค.
๊ธฐ๋ฅ์ ๊ตฌํํ๋ฉด์ html2canvas์ dom-to-image๋ฅผ ๋ชจ๋ ์ฌ์ฉํด ๋ดค์ต๋๋ค.
์ ๊ฐ ์ฌ์ฉํด ๋ณธ ๋ ๊ฐ์ง ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ํด์๋ ์ผ๋ฐ์ ์ผ๋ก ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ชจ๋ ์์ญ์ ์ ํํ๊ฒ ์บก์ฒํ๊ณ DOM ์์์ ์ ์ฉ๋ CSS ์คํ์ผ์ ์บก์ฒํ๋ ๋ฐ ํฐ ๋ฌธ์ ๋ ์์์ต๋๋ค.
๊ทธ๋ฌ๋ dom-to-image๊ฐ html2canvas๋ณด๋ค ๋ ๋น ๋ฅด๊ณ ์์ ์ ์ด๋ผ๊ณ ํ๋ ์ฌ์ฉ์๋ ์๋ค๊ณ ํฉ๋๋ค.
๋ํ, dom-to-image๋ ๋ ์์ ๋ฒ๋ค ํฌ๊ธฐ(์ฝ 14kb)๋ฅผ ๊ฐ๋ ๋ฐ๋ฉด html2canvas๋ ๋ ํฐ ๋ฒ๋ค ํฌ๊ธฐ(์ฝ 140kb)๋ฅผ ๊ฐ๋๋ค๋ ๊ฒ์ ๊ณ ๋ คํด ๋ณผ ์ ์์ต๋๋ค.
๋ฐ๋ผ์ ๋ฒ๋ค ํฌ๊ธฐ๊ฐ ์ค์ํ ๊ฒฝ์ฐ dom-to-image๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ์ข์ ์ ์์ต๋๋ค.
๊ทธ๋ฌ๋ ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํฐ ์ฐจ์ด์ ์ค ํ๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ฒ๋ฆฌํ๋ ๊ธฐ๋ฅ์ ๋ฒ์์ ๋๋ค.
html2canvas๋ SVG ๋ฐ Canvas ์์๋ ์บก์ฒํ ์ ์์ผ๋ฏ๋ก ๋ ๋ค์ํ ์์์ ๋ํ ์บก์ฒ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
์ค์ ๋ก, ๊ฐ๋ฐํ๋ฉด์ DOM์์ ์์ img ํ์ผ์ด ํฌํจ๋์ด ์๋ ์ํฉ์์ dom-to-image๋ imgํ์ผ์ ์ธ์ํ์ง ๋ชปํ์ฌ imgํ์ผ์ด ๊นจ์ ธ์ ์บก์ฒ๋๋ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ์ ์์ด์ dom-to-image์์ html2canvas๋ก ๋ณ๊ฒฝํ์ต๋๋ค.
SVG ๋ฐ Canvas๋ฅผ ํฌํจํ ๋ค์ํ ์์์ ๋ํ ์บก์ฒ๊ฐ ํ์ํ ๊ฒฝ์ฐ html2canvas๋ฅผ ์ ํํ๋ ๊ฒ์ด ์ต์ ์ด๋ผ๊ณ ํ ์ ์์ต๋๋ค.
๊ทธ๊ฒ์ด ์๋๋ผ๋ฉด ๊ฐ๋ณ๊ณ ๋น ๋ฅธ dom-to-image๋ฅผ ์ ํํ๋ ๊ฒ์ด ์ต์ ์ธ ๊ฒ ๊ฐ์ต๋๋ค.
html2canvas์ dom-to-image๋ก ์ฝ๋๋ฅผ ์์ฑํ๋ ๋ถ๋ถ์ ๋งค์ฐ ์ ์ฌํ๊ณ ์ฝ๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ๊ฑฑ์ ์ ํ์ง ์์๋ ๋ฉ๋๋ค.
๊ทธ๋๋ html2canvas๊ฐ ํ์ฌ๋ ์๋์ ์ผ๋ก ๋ง์ด ์ฌ์ฉ๋๊ณ ์์ต๋๋ค.
html2canvas
์ฌ์ฉ์ ๋ธ๋ผ์ฐ์ ์์ ์ง์ ์น ํ์ด์ง ๋๋ ๊ทธ ์ผ๋ถ์ "์คํฌ๋ฆฐ์ท"์ ์ฐ์ ์ ์๋ค. ์คํฌ๋ฆฐ์ท์ DOM์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ค.
์บก์ฒํ ์์ญ (DOM)์ ์ง์ ํ๊ณ ํด๋น ์์ญ์ ๋ํ ์คํฌ๋ฆฐ์ท์ ์ฐ์ ์ ์๋๋ก ๋์์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
https://html2canvas.hertzen.com/
html2canvas - Screenshots with JavaScript
Try out html2canvas Test out html2canvas by rendering the viewport from the current page. Capture
html2canvas.hertzen.com
์ค์น ๋ฐฉ๋ฒ
npm install html2canvas
or
yarn add html2canvas
๊ธฐ๋ณธ์ ์ธ ์ฌ์ฉ ๋ฐฉ๋ฒ ์์
const saveAsImageHandler = () => {
const target = document.getElementById('content');
if (!target) {
return alert('๊ฒฐ๊ณผ ์ ์ฅ์ ์คํจํ์ต๋๋ค.');
}
html2canvas(target).then((canvas) => {
const link = document.createElement('a');
document.body.appendChild(link);
link.href = canvas.toDataURL('image/png');
link.download = 'result.png';
link.click();
document.body.removeChild(link);
});
};
html2canvas์ ๋ํ ์ฌ์ฉ ๋ฐฉ๋ฒ์ ์ฐพ์๋ณด๋ฉด ๋ณดํต ์ด๋ฐ ์์ผ๋ก ๋ง์ด ๊ธฐ๋ฅ์ ์์ฑํ๋ ์์ ๋ฅผ ๋ง์ด ์ฐพ์๋ณผ ์ ์์ต๋๋ค.
ํ์ง๋ง ์ด๋ ๊ฒ a tag๋ฅผ ํตํด์ ์ฝ๋๋ฅผ ์์ฑํ์ ๋ PC์์๋ ์ ํ ๋ฌธ์ ๊ฐ ์์์ผ๋, IPhone ๊ธฐ์ค Safari ๋ธ๋ผ์ฐ์ ์ธ์ ๋ชจ๋ ์๋ํ์ง ์์์ต๋๋ค.
Android์์๋ ํ ์คํธ๋ฅผ ํด๋ณผ ์๊ฐ ์์ด์ ๋น์ทํ ์ํฉ์ผ๋ก ๊ตฌ๊ธ๋ง์ ํด๋ณธ ๊ฒฐ๊ณผ Samsung Phone์์ ์๋ ๋ค์ด๋ก๋๋ฅผ ์ฐจ๋จํด ๋์ ๊ฒ์ผ๋ก ํ์ธ ๋์ต๋๋ค.
file-saver
์์์ ๋งํ ๋ฌธ์ ์ ์ ํด๊ฒฐํ๊ธฐ ์ํด ํด๋ผ์ด์ธํธ์์ ํ์ผ ์ ์ฅ์ ๋์์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ file-saver๊ฐ ์์ต๋๋ค.
file-saver๋ฅผ ์ฌ์ฉํ๋ฉด PC, Mobile ๊ฐ ํ๊ฒฝ๊ณผ ์ฌ๋งํ ๋ธ๋ผ์ฐ์ ๋ชจ๋ ํธํ์ด ๋๋๋ก ํด์ฃผ๋ ๊ธฐ๋ฅ์ ํด์ฃผ๊ณ ์๊ณ , ๊ฐ๋จํ ์ฝ๋๋ก ํ์ผ์ blob, file, url ํ์์ ๋ํ ํ์ผ๋ก ์ ์ฅํ๋ ๊ฒ์ ์ ์ฅํ ์ ์๋๋ก ๋์์ฃผ๊ณ ์์ต๋๋ค.
https://www.npmjs.com/package/file-saver
file-saver
An HTML5 saveAs() FileSaver implementation. Latest version: 2.0.5, last published: 2 years ago. Start using file-saver in your project by running `npm i file-saver`. There are 3981 other projects in the npm registry using file-saver.
www.npmjs.com
์ค์น ๋ฐฉ๋ฒ
npm install file-saver --save
or
yarn add file-saver
ํ์ ์คํฌ๋ฆฝํธ ํ๊ฒฝ์์๋ ํ์ ์ ์๋ ๋ฐ๋ก ์ค์น๋ฅผ ํด์ค์ผ ํฉ๋๋ค.
npm install @types/file-saver --save-dev
or
yarn add @types/file-saver -D
html2canvas + file-saver
๊ทธ๋ผ ์ด์ html2canvas์ file-saver๋ฅผ ํตํด์ ์ด๋ป๊ฒ ์ ์ฅ ๊ธฐ๋ฅ์ ๊ตฌํํ ์ง ์์๋ณด๊ฒ ์ต๋๋ค.
๋จผ์ ๊ฐ๋ฐ ํ๊ฒฝ์ React + TypeScript ํ๊ฒฝ์ ๋๋ค.
์์ ์ฝ๋
import "./styles.css";
import html2canvas from "html2canvas";
import saveAs from "file-saver";
import { useRef } from "react";
export default function App() {
const divRef = useRef<HTMLDivElement>(null);
const handleDownload = async () => {
if (!divRef.current) return;
try {
const div = divRef.current;
const canvas = await html2canvas(div, { scale: 2 });
canvas.toBlob((blob) => {
if (blob !== null) {
saveAs(blob, "result.png");
}
});
} catch (error) {
console.error("Error converting div to image:", error);
}
};
return (
<div className="App">
<div
ref={divRef}
style={{ backgroundColor: "lime", width: "300px", height: "200px" }}
>
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
<button onClick={handleDownload}>๋ค์ด๋ก๋</button>
</div>
);
}
html2canvas์ ๋ ๋์๋ค๋๋ ๊ธฐ๋ณธ ์์ ์๋ querySelector๋ก DOM์์๋ฅผ ์ก์์ฃผ๋๋ฐ,
React ํ๊ฒฝ์์๋ useRef DOM์์๋ฅผ ๋ค๋ฃจ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ด๊ธฐ ๋๋ฌธ์ useRef๋ก ์บก์ฒ ์์ญ์ ์ง์ ํด ์ฃผ์์ต๋๋ค.
React์์ querySelector ๋์ useRef๋ก DOM์ ๋ค๋ค์ผ ํ๋ ์ด์
- React ์ ์ธ์ ๋ฐฉ์์ ์ ํฉ: useRef๋ React์ ์ ์ธ์ ๋ฐฉ์์ ๋ณด๋ค ์ ํฉํฉ๋๋ค. React์์๋ UI๋ฅผ ์์ฑํ ๋ ์ ์ธ์ ์ธ ์ฝ๋ ์คํ์ผ์ ์ฌ์ฉํ๋ฏ๋ก, useRef๋ฅผ ์ฌ์ฉํ๋ฉด ์ฝ๋์ ์ผ๊ด์ฑ์ด ์ ์ง๋๊ณ ๋ฆฌ์กํธ์ ์ธ ๊ฐ๋ฐ ์ต๊ด์ ์งํฌ ์ ์์ต๋๋ค.
- ์ง์ ์กฐ์ ์ต์ํ: React๋ ์ปดํฌ๋ํธ์ ์ํ์ ๋ ๋๋ง์ ๊ด๋ฆฌ๋ฅผ ๋์์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. querySelector์ ๊ฐ์ ์์ JavaScript ์ฝ๋๋ฅผ ์ฌ์ฉํ๋ฉด, ์ง์ DOM ์กฐ์์ด ํ์ํ๋ฏ๋ก ๋ฆฌ์กํธ์ ์ฒ ํ์ ์ด๊ธ๋ฉ๋๋ค. useRef๋ DOM์ ๋ํ ์ฐธ์กฐ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์์ด ์ํ ๋ณ๊ฒฝ ์ React๊ฐ ์ํํ๋ ๋ ๋๋ง ์ต์ ํ๋ฅผ ๋ฐฉํดํ์ง ์์ต๋๋ค.
- ๋ฆฌ๋ ๋๋ง์ ์์ : querySelector๋ ๋ ๋๋ง ์๋ง๋ค ํธ์ถ๋์ด์ผ ํ๋ฉฐ, ๊ฒฐ๊ณผ์ ์ผ๋ก ์ฌ๋ฌ ๋ฒ DOM์ ์ฐพ์์ผ ํ๋ ๋ฐ๋ฉด, useRef๋ ํ ๋ฒ๋ง DOM์ ์ฐพ์์ ๊ณ์ ์ฐธ์กฐํ๋ฏ๋ก ๋ฆฌ๋ ๋๋ง์ ์์ ํ๊ณ ์ฑ๋ฅ์ ๋ ์ด์ ์ ์ค๋๋ค.
- ์ปดํฌ๋ํธ์ ์๋ช ์ฃผ๊ธฐ ์ ๋ฐ์ ์ฌ์ฉ ๊ฐ๋ฅ: useRef๋ React์ ๋ค์ํ ์๋ช ์ฃผ๊ธฐ์ ๊ด๋ จ Hook๋ค, ์๋ฅผ ๋ค์ด useEffect, useState, useCallback ๋ฑ๊ณผ ํจ๊ป ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด๋ก ์ธํด ๋ ์ ์ฐํ๊ฒ ์ฝ๋๋ฅผ ๊ตฌ์ฑํ ์ ์์ผ๋ฉฐ, ์ปดํฌ๋ํธ์ ์๋ช ์ฃผ๊ธฐ์ ์ํ์ ๋ฐ๋ผ ์ฐธ์กฐ๊ฐ์ ์ ๋ฐ์ดํธํ๊ฑฐ๋ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
์ด๋ฌํ ์ด์ ๋ก ์ธํด, React์์ DOM ์์๋ฅผ ๋ค๋ฃฐ ๋ useRef๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ๋ฌผ๋ก ํ์ํ ๊ฒฝ์ฐ(ํ์ธ ์ ์ฉ ์ฉ๋ ๋ฑ) querySelector๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ด์ฉ ์ ์์ง๋ง, ๊ฐ๋ฅํ ํ React ์ปดํฌ๋ํธ์ ์ํ์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ์งํฌ ์ ์๋ useRef๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
์บก์ฒํ ์์ญ์ ์ง์ ํด ์ฃผ๊ณ html2canvas์ ๋๊ฒจ์ฃผ๊ณ html2canvas๊ฐ ์บก์ฒํด ์ค ๊ฒ blob์ผ๋ก ๋ณํํ ๋ค์ file-saver๋ฅผ ํตํด์ ์ ์ฅ๋๋๋ก ํด์ฃผ์์ต๋๋ค.
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ ๊ธฐ๋ฅ์ ๊ตฌํํ๋ ์ฝ๋ ์์ฒด๊ฐ ๋งค์ฐ ์ง๊ด์ ์ธ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
๐ ๋ง๋ฌด๋ฆฌ
html2canvas์ file-saver ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ํด์ ์์๋ดค์ต๋๋ค.
๊ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ ๋ํด ๋ค์ํ ์ต์ ๋ค๋ ์์ผ๋ ๊ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ํ ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ์๋ฉด ๋ฉ๋๋ค.