자바스크립트 PDF 합치기 구현: pdf-lib 활용 브라우저 로컬 병합

자바스크립트 PDF 합치기 구현: pdf-lib 활용 브라우저 로컬 병합

비즈니스 업무 자동화나 웹 지향 문서 관리 도구를 개발할 때, 복수의 PDF 파일들을 하나로 병합하는 기능은 매우 흔하게 요구되는 명세입니다. 전통적으로 이러한 작업은 서버 단(Node.js, Python, Java 등)으로 무거운 PDF 바이너리를 파일 업로드 전송한 뒤 백엔드 라이브러리를 사용해 처리하여 다시 프런트엔드로 리턴하는 복잡한 흐름을 거쳤습니다.

그러나 서버 측 병합은 대용량 파일 전송 시 통신 지연이 발생하고, 동시 요청이 많을 경우 서버 메모리 및 CPU 연산 부담이 심화됩니다. 무엇보다 주민등록등본, 금융 계약서 등 민감한 정보가 담긴 대외비 문서를 온라인 서버에 임시로라도 업로드해야 하므로 보안 취약점이 항상 도사리고 있습니다. 이러한 단점을 완전히 지워버리는 아키텍처가 바로 **브라우저 로컬 클라이언트 단독 PDF 병합(Client-Side PDF Merging)**입니다. 본 가이드에서는 자바스크립트 생태계의 대표적인 PDF 제어 패키지인 **pdf-lib**을 활용하여, 서버 연동 없이 100% 브라우저 메모리상에서 비동기로 파일들을 조합하고 내려받는 완성형 코드를 다룹니다.


1. 서버 측 PDF 병합 vs 브라우저 로컬 병합 아키텍처 대조

클라이언트 사이드에서 작동하는 PDF 병합은 사용자가 파일을 선택하면 브라우저의 FileReaderFile.arrayBuffer() API를 사용해 데이터를 바이너리 이진 배열(ArrayBuffer)로 읽어 들이고, 프론트엔드 웹 컴파일 환경에서 PDF 문서 객체를 직접 인스턴스화하여 페이지들을 병합하는 구조를 가집니다.

이 기법은 보안성 향상 외에도 인프라 관리 관점에서 대단히 획기적인 이점을 선사합니다. 서버 단의 대용량 연산 자원 비용이 0원이 되기 때문에 완전 무료 트래픽 기반 유틸리티 툴을 배포하기에 가장 이상적인 설계입니다.

비교 항목 백엔드 서버 측 병합 (Server-Side) 브라우저 로컬 병합 (Client-Side)
데이터 보안 및 유출 위험 서버 전송 과정에서 가로채기 및 임시 디스크 보존 취약점 존재 0% (데이터가 사용자 기기를 전혀 벗어나지 않음)
인프라 비용 대용량 PDF 파싱을 위한 고성능 CPU/RAM 서버 유지 비용 발생 0원 (사용자 기기의 CPU/RAM 연산 자원 활용)
속도 및 레이턴시 파일 업로드/다운로드 전송 통신 대기 시간 필수적 로컬 메모리 즉시 처리 (네트워크 전송 지연 시간 없음)
브라우저 메모리 한계 서버 메모리가 허용하는 한 용량 제한 없음 저사양 모바일 기기 등에서는 가용 메모리 한계 존재 가능

2. pdf-lib을 활용한 비동기 병합 코드 구현

본격적으로 pdf-lib 라이브러리를 탑재해 여러 PDF 파일을 병합하는 모듈을 구현해 보겠습니다. 브라우저 환경에서 작동하는 자바스크립트 ES6 문법을 기준으로 작성되었습니다.

1) CDN 또는 npm 패키지 설치

  • CDN (HTML script 태그 사용 시):
    <script src="https://unpkg.com/pdf-lib/dist/pdf-lib.min.js"></script>
    
  • npm (React, Next.js 등 모던 프레임워크 빌드 시):
    npm install pdf-lib
    

2) 비동기 PDF 병합 스크립트 핵심 코드

import { PDFDocument } from 'pdf-lib';

/**
 * 브라우저 로컬에서 복수의 PDF 파일을 병합하고 즉시 다운로드를 실행하는 함수
 * @param {File[]} pdfFiles - 사용자가 파일 input으로 선택한 File 객체 배열
 */
export async function mergePDFFiles(pdfFiles) {
  try {
    // 1. 마스터 합본이 될 새로운 빈 PDF 문서 객체 생성
    const mergedPdfDoc = await PDFDocument.create();

    // 2. 전달된 개별 PDF 파일들을 순차적으로 순회하며 페이지 병합
    for (const file of pdfFiles) {
      // 파일을 ArrayBuffer로 읽기
      const fileArrayBuffer = await file.arrayBuffer();
      
      // 개별 PDF 문서 인스턴스로 로드
      const pdfDoc = await PDFDocument.load(fileArrayBuffer);
      
      // 해당 PDF의 전체 페이지 수 추출
      const pageIndices = pdfDoc.getPageIndices();
      
      // 마스터 문서로 페이지 소유권 이전 및 복사 (copyPages)
      const copiedPages = await mergedPdfDoc.copyPages(pdfDoc, pageIndices);
      
      // 복사된 페이지들을 마스터 합본에 한 장씩 추가
      copiedPages.forEach((page) => {
        mergedPdfDoc.addPage(page);
      });
    }

    // 3. 병합이 완료된 마스터 문서를 바이너리 바이트(Uint8Array)로 저장
    const mergedPdfBytes = await mergedPdfDoc.save();

    // 4. 브라우저 로컬 다운로드를 위한 Blob 객체 및 임시 URL 스키마 생성
    const blob = new Blob([mergedPdfBytes], { type: 'application/pdf' });
    const downloadUrl = URL.createObjectURL(blob);
    
    // 5. 가상 A 태그 생성을 통한 강제 다운로드 트리거
    const link = document.createElement('a');
    link.href = downloadUrl;
    link.download = `merged_${Date.now()}.pdf`;
    document.body.appendChild(link);
    link.click();
    
    // 6. 다운로드 완료 즉시 가비지 컬렉터를 유도하기 위해 메모리 해제
    document.body.removeChild(link);
    URL.revokeObjectURL(downloadUrl);
    
    return true;
  } catch (error) {
    console.error("PDF 병합 중 예외 발생:", error);
    throw error;
  }
}

3. 대용량 PDF 처리 시의 성능 최적화 요령

클라이언트 사이드 연산은 사용자 기기의 하드웨어 리소스에 전적으로 의존하므로 다음 주의점을 충족해야 모바일 웹 브라우저가 강제 종료(Crash)되는 현상을 막을 수 있습니다.

  • 동시 복사 억제: 다중 루프 내에서 대량의 페이지를 한 번에 복사할 때 Array.map 등으로 병렬 비동기 처리를 유도하면 메모리가 순간 급증합니다. 위 코드 예시처럼 for...of를 통해 순차적 동기 루프로 한 파일씩 가공해 올리는 것이 모바일 브라우저 환경에서 안전합니다.
  • 페이지 선별 병합: 모든 페이지를 합치는 대신 copyPages의 두 번째 인자인 인덱스 배열을 조작하여 특정 페이지(예: 홀수 페이지 또는 1~5페이지 범위)만 선별적으로 추출하여 마스터 문서에 끼워 넣는 방식으로 뷰어 기능과 결합할 수 있습니다.

4. 자주 묻는 질문 (FAQ)

Q1. pdf-lib을 쓸 때 암호화된 PDF 문서는 어떻게 합치나요?

암호가 걸려 잠겨있는 PDF는 PDFDocument.load(bytes) 호출 단계에서 에러가 납니다. 사용자에게 비밀번호를 입력받아 load 함수의 옵션 파라미터로 { ignoreEncryption: false } 또는 암호 키 스트링을 넘겨 복호화한 후 복사 과정을 이어가야 합니다.

Q2. 병합 전 파일의 서명(Signature)이나 폼 입력 데이터가 보존되나요?

copyPages를 통해 페이지를 추출하여 새 문서로 이식할 경우, 기존 PDF에 내장되어 있던 디지털 서명이나 인터랙티브 아키텍처의 입력 필드(AcroForm) 상태 값 정보는 일부 유실되거나 해제될 수 있습니다. 폼 데이터를 그대로 유지하고 싶다면 pdf-lib에서 지원하는 AcroForm 복사 메소드를 사용해 폼 소유권을 추가로 넘겨주어야 합니다.


5. 비공개 고속 PDF 병합기 도구 이용 및 테스트

자신이 짠 pdf-lib 병합 모듈의 작동 속도와 페이지 합산 결과를 직접 실시간으로 테스트해보고 싶다면, 저희가 배포한 100% 무설치 비공개형 PDF 병합기를 통해 로컬 자바스크립트의 병합 품질을 즉시 확인해 보세요. 아울러 다중 PDF 파일을 특정 이미지 규격으로 정교하게 렌더링하고 싶다면 고해상도 PDF 이미지 변환 표준 가이드 칼럼을 함께 참조하여 업무 자동화 설계를 완수해 보시기 바랍니다.

함께 보면 좋은 글

목록으로 돌아가기