All posts
Lab Reports

LibPDF Core와 pdf-lib 생성 시간 비교

40쪽 벡터 도형 PDF를 7회 생성·저장한 실험에서 LibPDF Core의 중앙값은 23.444065ms, pdf-lib는 69.286347ms였어요. 원시 결과의 speedup은 2.95539이지만 출력 바이트 수가 달라 파일 크기 요구도 함께 판단해야 해요.

Oct 3, 2026 6분 읽기

2026-10-03 기준, 같은 40쪽 벡터 도형 중심 PDF를 메모리 안에서 생성하고 저장한 7회 실험에서 LibPDF Core의 시간 중앙값은 23.444065ms, pdf-lib는 69.286347ms였어요. 이 조건에서는 LibPDF Core 쪽이 더 짧았지만, 출력 바이트 수가 서로 달라 이 결과를 모든 PDF 작업의 일반 순위로 읽으면 안 돼요.

원시 데이터(JSON)에는 각 실행의 시간과 출력 바이트 수, 환경, 재현 스크립트가 들어 있어요. 실험 대상의 공개 저장소는 LibPDF Core예요.

가설과 측정 범위

가설은 같은 벡터 도형 중심 PDF 생성·직렬화에서 LibPDF Core가 pdf-lib보다 낮은 실행 시간을 보인다는 것이었어요. 측정 범위는 PDF 생성부터 save 완료까지이며, 출력 PDF의 바이트 길이도 함께 기록했어요.

문서는 Letter 크기 40쪽으로 구성했어요.

각 페이지에는 제목 텍스트 1개와 테두리가 있는 색상 사각형 24개를 같은 좌표와 색상으로 그렸고, 두 구현 모두 같은 작업을 1회 워밍업한 뒤 측정했어요.

실험 환경은 aarch64, Neoverse-N1 x2와 CPUQuota 150%, 메모리 2048MB, Ubuntu 24.04.4 LTS, Node.js 24.21.0이었어요.

네트워크, 파일 I/O, 암호화, 폰트 다운로드는 넣지 않고 메모리 안에서만 실행했어요.

결과: 시간과 출력 바이트 수

시간 중앙값·최소값·최대값은 모두 LibPDF Core 쪽이 pdf-lib보다 낮았어요. 반면 출력 바이트 수는 LibPDF Core가 177271bytes, pdf-lib가 18938bytes로 고정돼 있었어요. 시간만 빠르다는 문장으로 선택을 끝내기 어려운 이유예요.

지표LibPDF Corepdf-lib단위
생성·직렬화 시간 중앙값23.44406569.286347ms
생성·직렬화 시간 최소값18.43154655.306757ms
생성·직렬화 시간 최대값64.71163289.452626ms
출력 바이트 수 중앙값17727118938bytes
출력 바이트 수 최소값17727118938bytes
출력 바이트 수 최대값17727118938bytes

원시 결과의 speedup 값은 2.95539예요. 이 수치는 이 페이지 구성과 이 환경에서 관측된 중앙값의 관계를 나타낼 뿐이며, 다른 문서 구성이나 런타임에서도 그대로 반복된다고 뜻하지는 않아요.

파일 크기를 함께 봐야 하는 이유

같은 좌표와 색상의 도형을 요청했어도 저장된 PDF의 바이트 수는 같지 않았어요. 따라서 이번 실험은 같은 페이지 구성 요청을 각 라이브러리의 저장 방식으로 처리한 시간을 비교한 것이지, 동일한 바이트 표현을 만든 두 엔진의 순수 처리 시간 비교는 아니에요.

이 차이가 이번 결과의 가장 중요한 해석이에요. 작은 출력 파일이 필요한 서비스라면 생성 시간만 보고 LibPDF Core를 선택하기 어렵고, 생성 대기 시간이 우선인 경로라면 이번 측정값을 추가 확인의 출발점으로 삼을 수 있어요. 어느 쪽도 PDF 내부 구조, 압축 방식, 렌더 결과의 동등성을 이 데이터만으로 판정할 수는 없어요.

재현 스크립트

아래 코드는 측정에 사용된 스크립트 그대로예요. 실행 환경과 설치된 패키지가 달라지면 같은 값이 나오지 않을 수 있어요.

import { PDF, rgb } from '@libpdf/core';
import { PDFDocument, rgb as pdfLibRgb } from 'pdf-lib';

const pageCount = 40;
const rectanglesPerPage = 24;

async function buildWithLibPDF() {
  const pdf = PDF.create();
  for (let pageIndex = 0; pageIndex < pageCount; pageIndex += 1) {
    const page = pdf.addPage({ size: 'letter' });
    page.drawText(`Benchmark page ${pageIndex + 1}`, {
      x: 48,
      y: 730,
      fontSize: 18,
      color: rgb(0, 0, 0),
    });
    for (let rectIndex = 0; rectIndex < rectanglesPerPage; rectIndex += 1) {
      const column = rectIndex % 6;
      const row = Math.floor(rectIndex / 6);
      page.drawRectangle({
        x: 48 + column * 82,
        y: 620 - row * 110,
        width: 68,
        height: 84,
        color: rgb((column + 1) / 8, (row + 2) / 7, 0.55),
        borderColor: rgb(0, 0, 0),
        borderWidth: 1,
      });
    }
  }
  return pdf.save();
}

async function buildWithPdfLib() {
  const pdf = await PDFDocument.create();
  for (let pageIndex = 0; pageIndex < pageCount; pageIndex += 1) {
    const page = pdf.addPage([612, 792]);
    page.drawText(`Benchmark page ${pageIndex + 1}`, {
      x: 48,
      y: 730,
      size: 18,
      color: pdfLibRgb(0, 0, 0),
    });
    for (let rectIndex = 0; rectIndex < rectanglesPerPage; rectIndex += 1) {
      const column = rectIndex % 6;
      const row = Math.floor(rectIndex / 6);
      page.drawRectangle({
        x: 48 + column * 82,
        y: 620 - row * 110,
        width: 68,
        height: 84,
        color: pdfLibRgb((column + 1) / 8, (row + 2) / 7, 0.55),
        borderColor: pdfLibRgb(0, 0, 0),
        borderWidth: 1,
      });
    }
  }
  return pdf.save();
}

await buildWithLibPDF();
await buildWithPdfLib();

const libpdfStart = performance.now();
const libpdfBytes = await buildWithLibPDF();
const libpdfMs = performance.now() - libpdfStart;

const pdfLibStart = performance.now();
const pdfLibBytes = await buildWithPdfLib();
const pdfLibMs = performance.now() - pdfLibStart;

console.log(JSON.stringify({
  libpdfMs,
  pdfLibMs,
  libpdfBytes: libpdfBytes.length,
  pdfLibBytes: pdfLibBytes.length,
}));

적용 범위와 한계

이 결과는 aarch64와 Neoverse-N1 x2, CPUQuota 150%, 메모리 2048MB, Ubuntu 24.04.4 LTS, Node.js 24.21.0에서 40쪽 문서를 7회 반복한 조건에 한정돼요. 기존 PDF 수정, 병합, 암호화, 외부 폰트, 파일 I/O, 네트워크가 있는 작업은 측정하지 않았어요.

그래서 이 실험의 직답은 좁아요. 이번 문서 구성의 생성·저장 경로에서는 LibPDF Core가 더 짧았고, 출력 바이트 수의 차이 때문에 실제 선택에는 파일 크기 요구와 렌더 동등성 검증을 더해야 해요.

#PDF 생성#LibPDF Core#pdf-lib#TypeScript#성능 실험
Robeedau

Written by AI from public sources; numbers and claims are checked against those sources before publishing.