개요
프로젝트에서 UI 요소를 선택할 때, 기존에는 UI 요소의 이름만 보고 선택하는 방식이였기 때문에 가시성이 떨어짐
UI 요소의 이미지를 함께 보여준다면 사용자가 쉽게 선택할 수 있을 것이고 가시성이 올라갈 것이라 판단!
따라서 UI 요소의 DOM을 캡처하여 썸네일을 보여주는 기능 구현
화면 캡처 라이브러리 조사
화면(DOM) 캡쳐 및 저장 기능을 구현하기에 앞서, React에서 어떤 라이브러리를 제공하고 있는지 알아보자!
또 그들의 장단점은 무엇인지 그래서 어떤 라이브러리를 사용하는 것이 좋은지 각자 판단해보기 ❤️🔥
`html2canvas`, `dom-to-image`, `html-to-image`
1. html2canvas
장점
- 널리 사용되고 검증된 라이브러리로, 오랜 기간 동안 많은 프로젝트에서 사용됨
- proxy 기능을 지원하며 다양한 웹 브라우저에서 안정적으로 작동함
- CSS 스타일 지원: 캡처하려는 DOM의 CSS 스타일을 상당 부분 유지하며 캡처 가능
- Cross-Origin 이미지 핸들링 : CORS를 지원하며, 타 도메인의 이미지를 포함하는 요소도 캡처 가능
단점
- SVG와 같은 특정 요소 지원 부족 : 복잡한 CSS 스타일이나 HTML 구조는 정확하게 변환되지 않을 수 있음
- 속도 : HTML 구조가 복잡하거나 대규모 DOM 요소를 캡처할 경우 랜더링 속도가 느려질 수 있음
- 확장성 부족: 이미지 포멧이나 특수한 캡처 작업에 대한 유연성이 부족할 수 있음
사용 예제
import html2canvas from 'html2canvas';
html2canvas(document.querySelector("#capture")).then(canvas => {
const imgData = canvas.toDataURL("image/png");
// 이미지 저장
});
2. dom-to-image
장점
- 유연한 SVG 지원: DOM을 SVG 형식으로 변환한 뒤 이미지를 생성하므로, SVG 요소와 같은 복잡한 DOM을 잘 처리함
- 다양한 이미지 포멧 지원 : PNG, JPEG, SVG 등 여러 이미지 포멧으로 캡처한 DOM을 저장할 수 있음
- 빠른 처리 속도 : HTML이 복잡하지 않다면 대체로 속도가 빠름
단점
- 브라우저 의존성 : 일부 브라우저 환경에서 예상치 못한 동작을 보일 수 있음
- CSS 지원 한계 : 일부 CSS 애니메이션이나 특정 폰트가 올바르게 랜더링 되지 않을 수 있음
사용 예제
import domtoimage from 'dom-to-image';
domtoimage.toPng(document.getElementById('capture'))
.then(function (dataUrl) {
const img = new Image();
img.src = dataUrl;
document.body.appendChild(img);
});
3. html-to-image
장점
- 경량화된 최신 라이브러리: dom-to-image에서 파생된 경량화된 라이브러리로, 최신 웹 기술에 최적화되어 있고 버그 수정 및 성능 개선이 잘 이루어져 있음
- SVG와 같은 복잡한 요소 처리 : dom-to-image와 비슷하게 SVG와 같이 복잡한 요소를 잘 처리함
- CSS 스타일 유지: 기본적인 CSS 스타일을 충실히 재현하며, 많은 경우에 스타일을 잘 반영함
- 빠른 랜더링 속도: 최신 브라우저에 최적화되어 있어 대체로 빠른 속도를 보임
단점
- Cross-Origin 이슈: html2canvas처럼 CORS 처리가 필요하며, 서버 설정에 따라 일부 이미지가 로드되지 않을 수 있음
- 상대적으로 작은 커뮤니티: 다른 라이브러리에 비해 역사가 짧아, 상대적으로 작은 커뮤니티
사용 예제
import { toPng } from 'html-to-image';
toPng(document.getElementById('capture'))
.then((dataUrl) => {
const img = new Image();
img.src = dataUrl;
document.body.appendChild(img);
});
화면 캡처 기능 구현 START !
1. 내가 선택한 라이브러리는 ?!
내 프로젝트에 맞는 화면 캡처 라이브러리는 `html-to-image`라고 판단!
아래는 그 이유 ~~~~~
- 화면 캡처 로직을 컴포넌트 뿐만 아니라 페이지 캡처 시에도 사용할 예정
- DOM이 크고 복잡하다면 성능이 중요한 요소가 됨 (이 경우 비효율적인 라이브러리는 성능 저하를 초래할 수 있음)
- 많은 이미지나 복잡한 애니메이션을 캡처해야 한다는 것을 고려하였을 때 최적화된 라이브러리가 필요함
다들 본인 프로젝트에 맞는 라이브러리를 선택해라
2. 설치
npm install html-to-image
// or
yarn add html-to-image
3. DOM 요소를 활용해 PNG 생성 로직
async function createThumbnailPNG(id: string): Promise<string | null> {
const element = document.getElementById(id);
if (!element) return null;
const { width, height } = element.getBoundingClientRect();
const scale = Math.max(Math.min(22 / width, 16 / height), 0.5);
try {
return await toPng(element, {
pixelRatio: Math.min(2, scale),
width,
height,
canvasWidth: Math.max(width * scale, 1),
canvasHeight: Math.max(height * scale, 1),
skipFonts: true,
style: { margin: '0', padding: '0' },
});
} catch {
return null;
}
}
📌 코드 설명
- DOM 요소 찾기
- `document.getElementById(id)`로 요소를 찾고, 없으면 null 반환
- 크기 조절을 위한 비율 계산 (scale)
- 요소의 크기를 기준으로 `scale`을 계산하여 너무 작거나 큰 경우를 방지
- `Math.min(22 / width, 16 / height)` → 최대 크기 제한
- `Math.max(..., 0.5)` → 최소 크기 제한 (너무 작아지지 않도록)
- toPng 호출하여 PNG 이미지 생성
- `pixelRatio: Math.min(2, scale)` → 2배 이상 크기가 커지지 않도록 설정
- `canvasWidth`, `canvasHeight` → 캔버스 크기 계산
- `skipFonts: true `→ 폰트 로딩을 무시하여 속도 향상
- `style: { margin: '0', padding: '0' }` → 스타일 초기화
- 에러 처리
- 이미지 생성 중 오류 발생 시 null 반환
4. 썸네일 저장을 위해 PNG URL을 활용한 File 생성 로직
export async function createComponentThumbnailFile(id: string) {
const url = await createThumbnailPNG(id);
if (!url) return;
try {
const [meta, data] = url.split(',');
const mime = meta.match(/:(.*?);/)?.[1] || 'image/png';
const u8arr = Uint8Array.from(atob(data), c => c.charCodeAt(0));
return new File([u8arr], `${mime.split('/')[1]}`, { type: mime });
} catch (error) {
console.log('Thumbnail File Upload 실패:', error);
}
}
📌 코드 설명
- 썸네일 생성
- `createThumbnailPNG(id)`를 호출하여 썸네일 URL을 생성
- 실패하면 return으로 종료
- Base64 데이터를 Blob 형태로 변환
- `split(',')`을 사용해 Base64 URL에서 메타데이터(data:image/png;base64,...)와 실제 데이터를 분리
- 정규식으로 mime(MIME 타입) 추출, 기본값을 `image/png`으로 설정
- Uint8Array 변환
- `atob(data)`로 Base64를 바이너리 문자열로 변환.
- `Uint8Array.from(atob(data), c => c.charCodeAt(0))`를 사용하여 더 간결하게 변환
- File 객체 생성
- `new File([...], '파일명.확장자', { type: mime })`으로 파일 객체 반환
- 에러 처리
- 예외 발생 시 `console.log('Thumbnail File Upload 실패:', error)` 로그 출력 후 종료
마무리
화면 캡처 라이브러리 `html-to-image` 링크는 다음과 같다 ~ 더 궁금한 내용이 있으면 찾아보시길 ~~!
html-to-image
Generates an image from a DOM node using HTML5 canvas and SVG.. Latest version: 1.11.13, last published: 19 days ago. Start using html-to-image in your project by running `npm i html-to-image`. There are 369 other projects in the npm registry using html-to
www.npmjs.com
'👩💻 Programming > React' 카테고리의 다른 글
[WEB] Axios의 정의와 Interceptors 초기 세팅 (0) | 2025.03.03 |
---|---|
[React] 환경 변수 파일 .env란? (0) | 2023.07.07 |
MobX 상태 관리 라이브러리 (0) | 2023.04.11 |
[RN] React Native의 작동 원리 (0) | 2023.03.17 |
[RN] 상태관리 라이브러리 Redux란 ? (0) | 2023.03.02 |