React Fabric.js - 캔버스 전체 영역 이미지 저장 및 다운로드하기
Fabric.js 캔버스 전체 영역 이미지 다운로드 (React.js)
자꾸 보이는 영역만 썸네일 생성되고 이미지 다운로드돼서 작업하다 다른분들도 고생하실까싶어 작성해봄
작업 기존방식
최초엔 단순히 Fabric으로 생성된 canvas에 대해서 썸네일을 생성했었는데, 이걸 이용하다보니 현재 보이는 화면 기준으로만 썸네일이 뽑혀오는 현상이 발생했었습니다. (만약 현재 보이는 화면의 이미지만 캡쳐하고싶다면 아래 코드를 그대로 사용하셔도 됩니다)
//예시. thumbnail 생성
getThumbnailCanvas = () => {
return canvas.toDataURL({ format: 'png' })
}
전체영역으로 수정방식
현재 보이는 화면으로만 출력되는 현상을 수정하기 위하여 해당 canvas를 클론하여 내부 object content의 boundarie를 획득하여 해당 크기를 기준으로 새로운 캔버스를 생성 및 그 캔버스를 기준으로 썸네일을 생성하였습니다.
Fabric.js 캔버스 복제하기 (clone) 개념
Fabric.js에서는 canvas.clone()
을 사용하여 현재 캔버스를 복제할 수 있습니다. 이를 활용하면 원본 캔버스를 그대로 유지하면서, 새로운 캔버스에서 이미지 저장, 편집 등의 작업을 독립적으로 수행할 수 있습니다.
즉, 기존 캔버스를 직접 조작하지 않고도 클론 캔버스를 이용해 전체 크기 기준으로 이미지 변환이 가능합니다.
1. 이미지 썸네일 만들기
오브젝트의 사이즈가 너무 작을경우 썸네일이 너무 확대되는 현상이 있어서 사이즈를 1024 / 768 사이즈로 최소값을 설정해두었습니다.
generateFullScreenThumbnail() {
console.log("Generating full-screen thumbnail...");
return new Promise((resolve, reject) => {
const canvas = this.canvas;
// 1. 원본 캔버스 복제 (모든 객체 포함)
canvas.clone((clonedCanvas) => {
try {
// 2. 클론된 캔버스를 원본 크기(100%) 기준으로 설정
const boundaries = this.getCanvasContentBoundaries();
let { minX, minY, maxX, maxY, width, height } = boundaries;
console.log("boundaries:", boundaries);
// 3. 최소 크기 적용 (너비 1024 이상, 높이 768 이상)
const MIN_WIDTH = 1024;
const MIN_HEIGHT = 768;
const newWidth = Math.max(width, MIN_WIDTH);
const newHeight = Math.max(height, MIN_HEIGHT);
// 4. 중앙 정렬을 위한 이동 값 계산
const offsetX = (newWidth - width) / 2;
const offsetY = (newHeight - height) / 2;
// 5. 캔버스 크기 조정
clonedCanvas.setDimensions({ width: newWidth, height: newHeight });
// 6. 뷰포트 위치를 조정하여 중앙 정렬
clonedCanvas.viewportTransform = [1, 0, 0, 1, -minX + offsetX, -minY + offsetY];
clonedCanvas.setZoom(1);
clonedCanvas.renderAll();
// 7. 캔버스를 썸네일로 변환 (작은 크기로)
const thumbnailDataURL = clonedCanvas.toDataURL({ format: 'png', multiplier: 0.2 });
// 8. 썸네일 데이터 URL 반환
resolve(thumbnailDataURL);
} catch (error) {
reject(error);
}
});
});
}
2. 이미지 다운로드 만들기
handleSaveCanvasImagesFullScreen() {
const canvas = this.canvas;
// 1. 원본 캔버스 복제 (모든 객체 포함)
canvas.clone((clonedCanvas) => {
// 2. 클론된 캔버스를 원본 크기(100%) 기준으로 설정
const boundaries = this.getCanvasContentBoundaries();
const { minX, minY, maxX, maxY, width, height } = boundaries;
console.log("boundaries:", boundaries)
clonedCanvas.setDimensions({ width : width, height : height });
const point = { x: width / 2, y: height / 2 };
const scale = 1;
clonedCanvas.zoomToPoint(point, scale);
clonedCanvas.setZoom(1); // 원본 배율(100%)로 설정
clonedCanvas.viewportTransform = [1, 0, 0, 1, -minX, -minY]; // 전체 영역 조정
clonedCanvas.renderAll();
const dataURL = clonedCanvas.toDataURL({ format: 'png', multiplier: 2 });
fetch(dataURL)
.then(res => res.blob()) // Data URL을 Blob으로 변환
.then(blob => {
saveAs(blob, `full_canvas.png`); // 이미지 저장
});
});
}
투명 배경이아닌 흰색 배경이 필요할경우
아래 코드를 추가하면 흰색 배경으로 추가가 가능합니다.
// 1. 배경을 흰색으로 설정
const whiteBackground = new fabric.Rect({
left: minX,
top: minY,
width: width,
height: height,
fill: '#FFFFFF',
selectable: false, // 선택 불가능하게 설정
evented: false, // 이벤트 비활성화
});
// 2. 캔버스 맨 아래 레이어에 배경 추가
clonedCanvas.add(whiteBackground);
clonedCanvas.sendToBack(whiteBackground);
clonedCanvas.renderAll();
캔버스 내 콘텐츠의 실제 크기 계산하기
Fabric.js에서 canvas.width
, canvas.height
를 사용하면 캔버스의 크기만 반환되지만, 캔버스 내 개별 오브젝트들의 실제 크기를 가져오려면 getBoundingRect()
함수를 사용해야 합니다.
아래와 같은 로직으로 캔버스 내 모든 객체의 최소, 최대 좌표를 찾아 전체 크기를 계산합니다.
const canvas = this.canvas;
const objects = canvas.getObjects();
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
objects.forEach((obj) => {
if (!obj.visible) return; // 숨겨진 오브젝트 제외
const bbox = obj.getBoundingRect(true); // 현재 뷰포트와 관계없이 실제 좌표 반환
minX = Math.min(minX, bbox.left);
minY = Math.min(minY, bbox.top);
maxX = Math.max(maxX, bbox.left + bbox.width);
maxY = Math.max(maxY, bbox.top + bbox.height);
});
Fabric.js 캔버스 이미지를 저장할 때 multiplier 옵션이란?
Fabric.js에서 toDataURL({ multiplier: value })
옵션을 사용하면 출력되는 이미지의 **해상도를 조정**할 수 있습니다.
multiplier: 1
(기본값) → 캔버스 원본 크기로 저장multiplier: 2
→ 캔버스 크기의 2배 해상도로 저장 (고해상도)multiplier: 0.2
→ 원본 크기의 20% 크기로 줄여 저장 (썸네일 용도)
즉, 위 코드에서 multiplier: 0.2
를 설정한 이유는, 기존 캔버스 크기의 20% 크기로 줄여 **작은 용량의 썸네일 이미지를 만들기 위해서**입니다.
'Dev > [Javascript] React...' 카테고리의 다른 글
({a, b, ...others}) 객체 구조 분해 할당으로 파라미터 다루기 (JavaScript Destructuring Assignment) (0) | 2025.02.04 |
---|---|
Chrome Javascript MediaDevices.getUserMedia() http Permission error (0) | 2023.09.22 |
React 클래스 변수와 State변수의 역할 및 차이 (1) | 2023.03.14 |
fakepath local image File path 로컬 이미지 미리보기 / createObjectURL - javascript (0) | 2023.02.20 |
[JavaScript] rest & delete 연산자 / 불변성을 유지하며 Object에서 내부 key 삭제하기 (0) | 2023.02.08 |