
React 앱에서 PDF를 즉석에서 생성할 때(회사 로고가 필요한 인보이스, 차트가 포함된 보고서, 서명이 들어간 인증서 등) 페이지에 래스터 이미지를 프로그래밍 방식으로 배치해야 합니다. 순수 JavaScript만으로는 PDF의 내부 구조에 쓸 수 없으며, 로고 하나를 얹기 위해 백엔드를 구축하는 것은 사실상 클라이언트 측 작업에 과한 것입니다.
Spire.PDF for JavaScript는 전체 PDF 엔진을 WebAssembly로 컴파일하므로 React 앱에서 PDF를 완전히 브라우저에서 만들고, 편집하고, 저장할 수 있습니다. 파일은 브라우저 내 가상 파일 시스템(VFS)을 통해 이동하므로 네트워크 왕복이 없습니다. PdfImage와 페이지 캔버스의 DrawImage 메서드를 사용하면 각 이미지가 표시되는 위치와 크기를 정확하게 제어할 수 있습니다.
이 문서에서는 다음 방법을 알아봅니다:
- 이미지를 VFS에 로드하고
PdfImage객체로 변환 - 선택한 위치와 크기로 PDF 페이지에 이미지 그리기
- 새 PDF 문서와 기존 PDF 문서 모두에 이미지 추가
- 여러 페이지에서 이미지 크기 조정, 중앙 배치, 반복
- 완성된 PDF의 브라우저 다운로드 실행
브라우저에서 PDF를 생성하는 이유
일반적인 대안은 서버 측 라이브러리(iText, PDFBox 등)입니다. 브라우저가 자산을 업로드하고, 서버가 렌더링한 후 결과를 반환합니다. 이 방법도 작동하지만 이미지 삽입 작업에서는 다음과 같은 불편함이 있습니다:
- 지연 시간 — 모든 렌더링이 왕복을 기다리므로 대용량 파일이나 느린 연결 환경에서는 부담이 됩니다.
- 개인 정보 보호 — 원본 문서와 이미지가 사용자의 기기를 떠나므로 민감한 정보에는 문제가 됩니다.
- 비용 — PDF 렌더링은 CPU 사용량이 많고 무료로 확장되지 않습니다.
Spire.PDF for JavaScript를 사용하면 WebAssembly를 통해 전체 작업이 브라우저에서 실행됩니다. WASM 모듈이 로드되면 렌더링은 로컬에서 즉시 이루어지고 파일은 기기를 떠나지 않으며 서버 시간을 소비하지 않습니다.
전제 조건
이 연습에서는 이미 React 프로젝트에 Spire.PDF for JavaScript가 설치되어 있고 WASM 모듈이 초기화되어 있다고 가정합니다. 아니라면 먼저 React 프로젝트에 Spire.PDF for JavaScript 통합을 참조하세요.
필요한 항목:
- 프로젝트의
public폴더에 있는spire.pdf.base.js및spire.pdf.base.wasm파일 -
window.wasmModule.spirepdf를 통해 접근 가능한 WASM 모듈 - VFS에서 로드할 수 있는 위치에 삽입할 이미지(PNG, JPEG 등)
새 PDF에 이미지 추가
가장 간단한 시나리오는 완전히 새로운 PDF 문서를 만들고 첫 번째 페이지에 이미지를 그리는 것입니다. 핵심 단계는 다음과 같습니다:
-
이미지를 VFS에 로드 —
window.spire.FetchFileToVFS사용 -
PdfDocument를 만들고 빈 페이지 추가 -
PdfImage생성 — 로드된 파일에서PdfImage.FromFile사용 -
페이지 캔버스에 이미지 그리기 —
page.Canvas.DrawImage사용 - 결과 저장 및 다운로드
function App() {
const addImageToPdf = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check if the WASM module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the image into VFS
const inputImageName = 'TreePic.png';
await window.spire.FetchFileToVFS(inputImageName, "", `${process.env.PUBLIC_URL}/data/`);
// Create a PdfDocument object
let doc = new pdfModule.PdfDocument();
// Add a page
let page = doc.Pages.Add();
// Load the image and scale its display size proportionally
let image = pdfModule.PdfImage.FromFile(inputImageName);
let width = image.Width * 0.6;
let height = image.Height * 0.6;
// Calculate the horizontal center position and set the vertical position
let x = (page.Canvas.ClientSize.Width - width) / 2;
let y = 60;
// Draw the image at the specified position on the page
page.Canvas.DrawImage({ image: image, x: x, y: y, width: width, height: height });
// Define the output file name in PDF format
const outputFileName = 'AddImage.pdf';
// Save as PDF format
doc.SaveToFile({ fileName: outputFileName });
doc.Close();
// Read the generated PDF file from VFS and trigger download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Add Image To PDF</h1>
<button onClick={addImageToPdf}>
Generate
</button>
</div>
);
}
export default App;
이미지를 추가한 후 생성된 PDF 문서

코드가 하는 일:
-
PdfImage.FromFile(inputImageName)은 VFS에서 이미지를 읽어PdfImage객체를 만듭니다. 원본 픽셀 크기는image.Width및image.Height를 통해 확인할 수 있습니다. -
page.Canvas.DrawImage(...)는 페이지에 이미지를 렌더링합니다.x및y매개변수는 왼쪽 위 모서리 위치를 설정하고,width및height는 표시 크기를 제어합니다. - 이미지는 원래 크기의 60%(
* 0.6)로 조정되고(page.Canvas.ClientSize.Width - width) / 2를 사용하여 가로 중앙에 배치됩니다.
기존 PDF에 이미지 추가
기존 문서에 이미지를 추가하는 방법도 같은 패턴을 따릅니다. 유일한 차이점은 새 PdfDocument를 만드는 대신 VFS에서 문서를 로드하고 대상 페이지를 선택한다는 점입니다.
const addImageToExistingPdf = async () => {
const pdfModule = window.wasmModule?.spirepdf;
if (!pdfModule) return;
// Load both the PDF and the image into VFS
await window.spire.FetchFileToVFS('Report.pdf', "", `${process.env.PUBLIC_URL}/data/`);
await window.spire.FetchFileToVFS('Logo.png', "", `${process.env.PUBLIC_URL}/data/`);
// Load the existing PDF
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile('Report.pdf');
// Get the first page (or any page you want)
let page = doc.Pages.get_Item(0);
// Load the image and draw it at the top-right corner
let image = pdfModule.PdfImage.FromFile('Logo.png');
let imgWidth = 80;
let imgHeight = 40;
let x = page.Canvas.ClientSize.Width - imgWidth - 30; // 30pt margin from right edge
let y = 30; // 30pt from top
page.Canvas.DrawImage({ image: image, x: x, y: y, width: imgWidth, height: imgHeight });
// Save and download
const outputFileName = 'ReportWithLogo.pdf';
doc.SaveToFile({ fileName: outputFileName });
doc.Close();
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
새 문서 예제와의 주요 차이점: doc.LoadFromFile('Report.pdf')는 처음부터 새로 시작하는 대신 기존 PDF를 로드하고, doc.Pages.get_Item(0)는 로드된 문서에서 페이지를 가져옵니다. 나머지 그리기 로직은 동일합니다.
페이지에 이미 이미지가 있어서 새 이미지를 위에 추가하는 것이 아니라 그 이미지를 변경해야 하는 경우 JavaScript(React)에서 PDF의 이미지 교체 및 제거를 참조하세요.
크기 조정 및 위치 지정
DrawImage 메서드를 사용하면 이미지가 표시되는 위치와 크기를 완전히 제어할 수 있습니다. 가장 일반적인 패턴은 다음과 같습니다:
비율 크기 조정 — 가로와 세로를 같은 배율로 곱하여 종횡비를 유지합니다:
let scale = 0.5; // 50% of original size
let width = image.Width * scale;
let height = image.Height * scale;
고정 너비, 자동 높이 — 너비를 설정하고 종횡비를 유지하도록 높이를 계산합니다:
let targetWidth = 200;
let width = targetWidth;
let height = image.Height * (targetWidth / image.Width);
가로 중앙 정렬 — 이미지를 페이지 왼쪽 및 오른쪽 여백에서 동일한 거리에 배치합니다:
let x = (page.Canvas.ClientSize.Width - width) / 2;
세로 중앙 정렬 — 이미지를 페이지 위쪽과 아래쪽에서 동일한 거리에 배치합니다:
let y = (page.Canvas.ClientSize.Height - height) / 2;
사용자 지정 위치 — 절대 좌표를 사용합니다(원점은 왼쪽 위, 단위는 포인트, 1포인트 = 1/72인치):
let x = 72; // 1 inch from left
let y = 144; // 2 inches from top
여러 페이지에 이미지 추가
문서의 모든 페이지에 동일한 이미지(예: 로고 또는 워터마크)를 추가하려면 Pages 컬렉션을 반복합니다:
const addImageToAllPages = async () => {
const pdfModule = window.wasmModule?.spirepdf;
if (!pdfModule) return;
await window.spire.FetchFileToVFS('Business_Data_Overview.pdf', "", `${process.env.PUBLIC_URL}/data/`);
await window.spire.FetchFileToVFS('Logo.png', "", `${process.env.PUBLIC_URL}/data/`);
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile('Business_Data_Overview.pdf');
let image = pdfModule.PdfImage.FromFile('Logo.png');
let imgWidth = 60;
let imgHeight = 30;
// Loop through all pages and draw the logo in the top-right corner
for (let i = 0; i < doc.Pages.Count; i++) {
let page = doc.Pages.get_Item(i);
let x = page.Canvas.ClientSize.Width - imgWidth - 20;
let y = 20;
page.Canvas.DrawImage({ image: image, x: x, y: y, width: imgWidth, height: imgHeight });
}
const outputFileName = 'AllPagesWithLogo.pdf';
doc.SaveToFile({ fileName: outputFileName });
doc.Close();
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
이 패턴은 여러 페이지 문서 전체에 워터마크, 회사 로고 또는 페이지 스탬프를 균일하게 추가하는 데 유용합니다.
결과 다운로드
doc.SaveToFile()로 PDF를 VFS에 저장한 후에는 해당 파일을 다시 읽어 브라우저 다운로드를 실행해야 합니다. 이 두 단계 패턴(먼저 VFS에 저장한 다음 VFS에서 읽기)은 모든 Spire.PDF for JavaScript 예제에서 사용됩니다:
// 1. Save the PDF to the VFS
doc.SaveToFile({ fileName: 'Output.pdf' });
doc.Close();
// 2. Read the file from VFS as a byte array
const fileArray = window.dotnetRuntime.Module.FS.readFile('Output.pdf');
// 3. Create a Blob and trigger download
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'Output.pdf';
a.click();
URL.revokeObjectURL(url);
이미지를 저장할 때도 동일한 패턴이 적용됩니다(Blob 생성자에서 type: 'image/png' 또는 type: 'image/jpeg' 사용).
자주 묻는 질문
이미지의 위치와 크기를 정밀하게 제어하려면 어떻게 해야 하나요?
DrawImage의 x 및 y 매개변수는 이미지 왼쪽 위 모서리의 좌표(포인트 단위, 1포인트 = 1/72인치)를 설정합니다. width와 height 매개변수는 표시 크기를 설정합니다. 비율을 유지하며 크기를 조정하려면 image.Width와 image.Height를 읽고 둘 다 같은 배수로 곱하세요. 가로로 중앙 정렬하려면 x = (page.Canvas.ClientSize.Width - width) / 2로 계산합니다.
한 페이지에 여러 이미지를 추가할 수 있나요?
네. 이미지마다 page.Canvas.DrawImage(...)를 서로 다른 x/y 좌표로 호출하면 됩니다. 이미지는 메서드를 호출한 순서대로 그려지므로 겹치는 경우 나중에 그린 이미지가 먼저 그린 이미지 위에 표시됩니다.
지원되는 이미지 형식은 무엇인가요?
Spire.PDF for JavaScript는 PNG, JPEG, BMP, GIF를 포함한 일반적인 래스터 형식을 지원합니다. PdfImage.FromFile(filename)을 사용하여 VFS에서 이 형식들을 로드하세요.
이미지를 추가하면 페이지의 기존 콘텐츠에 영향을 주나요?
아니요. DrawImage는 기존 텍스트, 그래픽, 다른 이미지를 수정하지 않고 페이지에 새 이미지 객체를 추가합니다. 이미지는 지정된 좌표의 기존 콘텐츠 위에 그려집니다. 기존 PDF에서 이미지를 추출하여 다른 곳에서 재사용하려면 JavaScript(React)에서 PDF에서 이미지 추출을 참조하세요.