Python, Rust, Go에서 PDF 병합 및 분할하기
바인딩 지원 현황. PDF 병합은 Python, Rust, Go에서 사용할 수 있습니다.
extract_pages를 통한 파일 분할은 Python과 Rust에서 지원되며, 인메모리 버전인extract_pages_to_bytes는 Swift와 C ABI(WASM 제외)도 추가로 지원합니다. 북마크 기반 분할 계획(plan_split_by_bookmarks)은 Python, Rust, Swift, WASM, C ABI에서 사용할 수 있습니다. 파일 분할 바인딩의 경우, C# 바인딩은 아직 이 에디터 작업을 공개하지 않았습니다. 대안으로 Rust CLI(pdf-oxide merge,pdf-oxide split)를 사용하거나 지원되는 바인딩 중 하나를 통해 호출하세요.
두 개의 PDF를 하나로 병합하기:
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("main.pdf")
doc.merge_from("appendix.pdf")
doc.save("combined.pdf")
WASM
import { WasmPdfDocument } from "pdf-oxide-wasm";
// Load both PDFs as Uint8Array
const mainDoc = new WasmPdfDocument(mainBytes);
const appendixDoc = new WasmPdfDocument(appendixBytes);
// Extract text from both and process as needed
const allText = mainDoc.extractAllText() + "\n" + appendixDoc.extractAllText();
mainDoc.free();
appendixDoc.free();
Rust
use pdf_oxide::editor::DocumentEditor;
let mut editor = DocumentEditor::open("main.pdf")?;
editor.merge_from("appendix.pdf")?;
editor.save("combined.pdf")?;
Go
package main
import (
"log"
pdfoxide "github.com/yfedoseev/pdf_oxide/go"
)
func main() {
editor, err := pdfoxide.OpenEditor("main.pdf")
if err != nil { log.Fatal(err) }
defer editor.Close()
if _, err := editor.MergeFrom("appendix.pdf"); err != nil { log.Fatal(err) }
if err := editor.Save("combined.pdf"); err != nil { log.Fatal(err) }
}
C++
#include <pdf_oxide/pdf_oxide.hpp>
auto editor = pdf_oxide::DocumentEditor::open("main.pdf");
editor.merge_from("appendix.pdf");
editor.save("combined.pdf");
Swift
import PdfOxide
let editor = try DocumentEditor.open("main.pdf")
try editor.mergeFrom("appendix.pdf")
try editor.save("combined.pdf")
Dart
import 'package:pdf_oxide/pdf_oxide.dart';
final editor = DocumentEditor.open('main.pdf');
editor.mergeFrom('appendix.pdf');
editor.save('combined.pdf');
R
library(pdfoxide)
editor <- pdf_editor_open("main.pdf")
pdf_editor_merge_from(editor, "appendix.pdf")
pdf_editor_save(editor, "combined.pdf")
Julia
using PdfOxide
editor = open_editor("main.pdf")
merge_from(editor, "appendix.pdf")
save(editor, "combined.pdf")
Zig
const pdf_oxide = @import("pdf_oxide");
var editor = try pdf_oxide.DocumentEditor.openEditor("main.pdf");
defer editor.deinit();
try editor.mergeFrom("appendix.pdf");
try editor.save("combined.pdf");
Objective-C
#import "POXPdfOxide.h"
NSError *err = nil;
POXDocumentEditor *editor = [POXDocumentEditor openEditor:@"main.pdf" error:&err];
[editor mergeFrom:@"appendix.pdf" error:&err];
[editor saveToPath:@"combined.pdf" error:&err];
Elixir
{:ok, editor} = PdfOxide.open_editor("main.pdf")
:ok = PdfOxide.merge_from(editor, "appendix.pdf")
:ok = PdfOxide.editor_save(editor, "combined.pdf")
PDF Oxide는 PDF 객체 수준에서 페이지를 병합하므로 문서 간에 폰트, 이미지, 주석이 올바르게 보존됩니다.
설치
pip install pdf_oxide
PDF 병합
모든 페이지 병합
두 번째 PDF의 모든 페이지를 첫 번째 PDF에 추가하기:
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("report.pdf")
doc.merge_from("charts.pdf")
doc.save("full-report.pdf")
WASM
// WASM API: load and process multiple documents
const report = new WasmPdfDocument(reportBytes);
const charts = new WasmPdfDocument(chartsBytes);
// Process both documents together
const fullText = report.extractAllText() + "\n" + charts.extractAllText();
report.free();
charts.free();
Rust
let mut editor = DocumentEditor::open("report.pdf")?;
let pages_added = editor.merge_from("charts.pdf")?;
println!("Added {} pages", pages_added);
editor.save("full-report.pdf")?;
Go
editor, _ := pdfoxide.OpenEditor("report.pdf")
defer editor.Close()
added, _ := editor.MergeFrom("charts.pdf")
fmt.Printf("Added %d pages\n", added)
_ = editor.Save("full-report.pdf")
C++
auto editor = pdf_oxide::DocumentEditor::open("report.pdf");
editor.merge_from("charts.pdf");
editor.save("full-report.pdf");
Swift
let editor = try DocumentEditor.open("report.pdf")
try editor.mergeFrom("charts.pdf")
try editor.save("full-report.pdf")
Dart
final editor = DocumentEditor.open('report.pdf');
editor.mergeFrom('charts.pdf');
editor.save('full-report.pdf');
R
editor <- pdf_editor_open("report.pdf")
pdf_editor_merge_from(editor, "charts.pdf")
pdf_editor_save(editor, "full-report.pdf")
Julia
editor = open_editor("report.pdf")
merge_from(editor, "charts.pdf")
save(editor, "full-report.pdf")
Zig
var editor = try pdf_oxide.DocumentEditor.openEditor("report.pdf");
defer editor.deinit();
try editor.mergeFrom("charts.pdf");
try editor.save("full-report.pdf");
Objective-C
POXDocumentEditor *editor = [POXDocumentEditor openEditor:@"report.pdf" error:&err];
[editor mergeFrom:@"charts.pdf" error:&err];
[editor saveToPath:@"full-report.pdf" error:&err];
Elixir
{:ok, editor} = PdfOxide.open_editor("report.pdf")
:ok = PdfOxide.merge_from(editor, "charts.pdf")
:ok = PdfOxide.editor_save(editor, "full-report.pdf")
여러 파일 병합
정적 메서드 Pdf.merge()를 사용해 여러 PDF를 한 번에 합치기:
Python
from pdf_oxide import Pdf
pdf = Pdf.merge(["intro.pdf", "chapter1.pdf", "chapter2.pdf", "appendix.pdf"])
pdf.save("book.pdf")
기존 문서에 merge_from()을 연속으로 호출할 수도 있습니다:
from pdf_oxide import PdfDocument
doc = PdfDocument("intro.pdf")
for f in ["chapter1.pdf", "chapter2.pdf", "appendix.pdf"]:
doc.merge_from(f)
doc.save("book.pdf")
WASM
// Load and process multiple PDFs sequentially
const files = [introBytes, ch1Bytes, ch2Bytes, appendixBytes];
const allText = [];
for (const bytes of files) {
const doc = new WasmPdfDocument(bytes);
allText.push(doc.extractAllText());
doc.free();
}
console.log(allText.join("\n"));
Rust
let files = ["intro.pdf", "chapter1.pdf", "chapter2.pdf", "appendix.pdf"];
let mut editor = DocumentEditor::open(files[0])?;
for f in &files[1..] {
editor.merge_from(f)?;
}
editor.save("book.pdf")?;
Go
// Top-level Merge returns the combined PDF bytes in one call
bytes, err := pdfoxide.Merge([]string{
"intro.pdf", "chapter1.pdf", "chapter2.pdf", "appendix.pdf",
})
if err != nil { log.Fatal(err) }
_ = os.WriteFile("book.pdf", bytes, 0644)
C++
// Top-level merge returns the combined PDF bytes in one call
auto bytes = pdf_oxide::merge({"intro.pdf", "chapter1.pdf", "chapter2.pdf", "appendix.pdf"});
std::ofstream("book.pdf", std::ios::binary)
.write(reinterpret_cast<const char*>(bytes.data()), bytes.size());
Swift
// Top-level merge returns the combined PDF bytes in one call
let bytes = try merge(["intro.pdf", "chapter1.pdf", "chapter2.pdf", "appendix.pdf"])
try Data(bytes).write(to: URL(fileURLWithPath: "book.pdf"))
Dart
// Top-level pdfMerge returns the combined PDF bytes in one call
final bytes = pdfMerge(['intro.pdf', 'chapter1.pdf', 'chapter2.pdf', 'appendix.pdf']);
File('book.pdf').writeAsBytesSync(bytes);
R
# Top-level pdf_merge returns the combined PDF bytes in one call
bytes <- pdf_merge(c("intro.pdf", "chapter1.pdf", "chapter2.pdf", "appendix.pdf"))
writeBin(bytes, "book.pdf")
Julia
# Top-level merge_pdfs returns the combined PDF bytes in one call
bytes = merge_pdfs(["intro.pdf", "chapter1.pdf", "chapter2.pdf", "appendix.pdf"])
write("book.pdf", bytes)
Zig
const a = std.heap.page_allocator;
const paths = [_][*:0]const u8{ "intro.pdf", "chapter1.pdf", "chapter2.pdf", "appendix.pdf" };
const bytes = try pdf_oxide.merge(a, &paths); // combined PDF bytes
defer a.free(bytes);
const out = try std.fs.cwd().createFile("book.pdf", .{});
defer out.close();
try out.writeAll(bytes);
Objective-C
// Top-level merge returns the combined PDF bytes in one call
NSData *bytes = [POXTools merge:@[@"intro.pdf", @"chapter1.pdf", @"chapter2.pdf", @"appendix.pdf"]
error:&err];
[bytes writeToFile:@"book.pdf" atomically:YES];
Elixir
# Top-level merge returns the combined PDF bytes in one call
{:ok, bytes} = PdfOxide.merge(["intro.pdf", "chapter1.pdf", "chapter2.pdf", "appendix.pdf"])
File.write!("book.pdf", bytes)
특정 페이지만 병합
소스 문서에서 병합할 페이지를 선택하기:
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("main.pdf")
# Merge only pages 0, 2, and 4 from source
doc.merge_pages_from("source.pdf", [0, 2, 4])
doc.save("selected.pdf")
Rust
let mut editor = DocumentEditor::open("main.pdf")?;
editor.merge_pages_from("source.pdf", &[0, 2, 4])?;
editor.save("selected.pdf")?;
PDF 분할
페이지를 새 파일로 추출
큰 문서에서 특정 페이지를 추출하기:
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("book.pdf")
doc.extract_pages([0, 1, 2, 3, 4], "chapter1.pdf")
WASM
// Extract text from specific pages
const doc = new WasmPdfDocument(bytes);
const pages = [0, 1, 2, 3, 4];
for (const i of pages) {
const text = doc.extractText(i);
console.log(`Page ${i + 1}: ${text.slice(0, 80)}...`);
}
doc.free();
Rust
let mut editor = DocumentEditor::open("book.pdf")?;
editor.extract_pages(&[0, 1, 2, 3, 4], "chapter1.pdf")?;
개별 페이지로 분할
각 페이지를 별도 파일로 저장하기:
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("document.pdf")
for i in range(doc.page_count()):
doc.extract_pages([i], f"page_{i + 1}.pdf")
Rust
let mut editor = DocumentEditor::open("document.pdf")?;
let page_count = editor.page_count()?;
for i in 0..page_count {
editor.extract_pages(&[i], &format!("page_{}.pdf", i + 1))?;
}
청크 단위로 분할
큰 PDF를 N페이지씩 여러 개의 작은 파일로 분할하기:
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("large.pdf")
chunk_size = 10
for start in range(0, doc.page_count(), chunk_size):
end = min(start + chunk_size, doc.page_count())
pages = list(range(start, end))
doc.extract_pages(pages, f"chunk_{start // chunk_size + 1}.pdf")
Rust
let mut editor = DocumentEditor::open("large.pdf")?;
let page_count = editor.page_count()?;
let chunk_size = 10;
for start in (0..page_count).step_by(chunk_size) {
let end = (start + chunk_size).min(page_count);
let pages: Vec<usize> = (start..end).collect();
editor.extract_pages(&pages, &format!("chunk_{}.pdf", start / chunk_size + 1))?;
}
인메모리 바이트로 분할 (임시 파일 없음)
분할된 청크를 S3, HTTP 응답, 또는 같은 프로세스 내의 다음 단계로 바로 전달할 때는 extract_pages_to_bytes를 사용해 디스크 쓰기를 완전히 건너뛸 수 있습니다. 새 PDF를 바이트로 반환하며 원본 문서는 변경되지 않습니다.
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("large.pdf")
chunk_size = 10
chunks = []
for start in range(0, doc.page_count(), chunk_size):
end = min(start + chunk_size, doc.page_count())
pages = list(range(start, end))
chunk_bytes = doc.extract_pages_to_bytes(pages) # bytes, not a file
chunks.append(chunk_bytes)
print(f"Produced {len(chunks)} in-memory chunks")
Rust
let mut editor = DocumentEditor::open("large.pdf")?;
let page_count = editor.page_count()?;
let chunk_size = 10;
let mut chunks: Vec<Vec<u8>> = Vec::new();
for start in (0..page_count).step_by(chunk_size) {
let end = (start + chunk_size).min(page_count);
let pages: Vec<usize> = (start..end).collect();
chunks.push(editor.extract_pages_to_bytes(&pages)?); // Vec<u8>, no file written
}
Swift
let editor = try DocumentEditor(path: "large.pdf")
let pageCount = try editor.pageCount()
let chunkSize = 10
var chunks: [[UInt8]] = []
for start in stride(from: 0, to: pageCount, by: chunkSize) {
let end = min(start + chunkSize, pageCount)
chunks.append(try editor.extractPagesToBytes(Array(start..<end)))
}
C++
auto editor = pdf_oxide::DocumentEditor::open("large.pdf");
int page_count = editor.page_count();
const int chunk_size = 10;
std::vector<std::vector<std::uint8_t>> chunks;
for (int start = 0; start < page_count; start += chunk_size) {
int end = std::min(start + chunk_size, page_count);
std::vector<int32_t> pages;
for (int i = start; i < end; ++i) pages.push_back(i);
chunks.push_back(editor.extract_pages_to_bytes(pages)); // bytes, no file written
}
Dart
final editor = DocumentEditor.open('large.pdf');
final pageCount = editor.pageCount;
const chunkSize = 10;
final chunks = <Uint8List>[];
for (var start = 0; start < pageCount; start += chunkSize) {
final end = (start + chunkSize).clamp(0, pageCount);
final pages = [for (var i = start; i < end; i++) i];
chunks.add(editor.extractPagesToBytes(pages)); // bytes, no file written
}
R
editor <- pdf_editor_open("large.pdf")
page_count <- pdf_editor_page_count(editor)
chunk_size <- 10
chunks <- list()
for (start in seq(0, page_count - 1, by = chunk_size)) {
end <- min(start + chunk_size, page_count)
pages <- seq(start, end - 1)
chunks[[length(chunks) + 1]] <- pdf_editor_extract_pages_to_bytes(editor, pages)
}
Julia
editor = open_editor("large.pdf")
n = page_count(editor)
chunk_size = 10
chunks = Vector{Vector{UInt8}}()
for start in 0:chunk_size:(n - 1)
stop = min(start + chunk_size, n)
pages = collect(start:(stop - 1))
push!(chunks, extract_pages_to_bytes(editor, pages)) # bytes, no file written
end
Zig
const a = std.heap.page_allocator;
var editor = try pdf_oxide.DocumentEditor.openEditor("large.pdf");
defer editor.deinit();
const page_count = try editor.pageCount();
const chunk_size: i32 = 10;
var start: i32 = 0;
while (start < page_count) : (start += chunk_size) {
const end = @min(start + chunk_size, page_count);
var pages = std.ArrayList(i32).init(a);
defer pages.deinit();
var i = start;
while (i < end) : (i += 1) try pages.append(i);
const chunk = try editor.extractPagesToBytes(a, pages.items); // bytes, no file written
a.free(chunk);
}
Objective-C
POXDocumentEditor *editor = [POXDocumentEditor openEditor:@"large.pdf" error:&err];
NSInteger pageCount = [editor pageCountError:&err];
NSInteger chunkSize = 10;
NSMutableArray<NSData*> *chunks = [NSMutableArray array];
for (NSInteger start = 0; start < pageCount; start += chunkSize) {
NSInteger end = MIN(start + chunkSize, pageCount);
NSMutableArray<NSNumber*> *pages = [NSMutableArray array];
for (NSInteger i = start; i < end; i++) [pages addObject:@(i)];
[chunks addObject:[editor extractPagesToBytes:pages error:&err]]; // bytes, no file written
}
Elixir
{:ok, editor} = PdfOxide.open_editor("large.pdf")
{:ok, n} = PdfOxide.editor_page_count(editor)
chunk_size = 10
chunks =
0..(n - 1)
|> Enum.take_every(chunk_size)
|> Enum.map(fn start ->
stop = min(start + chunk_size, n)
{:ok, bytes} = PdfOxide.extract_pages_to_bytes(editor, Enum.to_list(start..(stop - 1)))
bytes
end)
extract_pages_to_bytes는 Python, Rust, Swift, C++, Dart, R, Julia, Zig, Objective-C, Elixir, 그리고 C ABI에서 사용할 수 있습니다. WASM 빌드에서는 제공되지 않습니다.
북마크로 분할
목차(개요)가 있는 문서의 경우, 페이지 범위를 직접 계산하지 않고 북마크 경계에서 분할 계획을 세울 수 있습니다. 예를 들어 최상위 챕터마다 PDF를 하나씩 만드는 방식이죠. plan_split_by_bookmarks는 드라이 런 플래너입니다. 세그먼트 계획(페이지 범위, 제목, 파일 시스템에 안전한 파일 이름)을 반환할 뿐 PDF 바이트는 생성하지 않으므로, 실제 파일을 쓰기 전에 미리보기, 필터링, 출력 대상 조정이 가능합니다.
분할 계획 세우기 (드라이 런)
Python
import pdf_oxide
with open("manual.pdf", "rb") as f:
src = f.read()
# level=1 -> split at top-level bookmarks only (0 = every depth, n = up to depth n)
segments = pdf_oxide.plan_split_by_bookmarks(src, level=1)
for seg in segments:
# keys: index, start_page, end_page, title, file_stem, page_label
print(f"#{seg['index']}: pages {seg['start_page']}-{seg['end_page'] - 1} "
f"=> {seg['file_stem']}.pdf ({seg['title']})")
Rust
use pdf_oxide::PdfDocument;
use pdf_oxide::split_bookmarks::{plan_split_by_bookmarks, SplitByBookmarksOptions, BookmarkLevel};
let doc = PdfDocument::open("manual.pdf")?;
let opts = SplitByBookmarksOptions {
level: BookmarkLevel::TopLevel, // top-level bookmarks only
..Default::default()
};
// Cheap: returns Vec<BookmarkSegment>, no PDF bytes produced
let segments = plan_split_by_bookmarks(&doc, &opts)?;
for seg in &segments {
println!("#{}: pages {}..{} => {}.pdf ({:?})",
seg.index, seg.start_page, seg.end_page, seg.file_stem, seg.title);
}
Swift
import PdfOxide
let doc = try PdfDocument(path: "manual.pdf")
// Returns a JSON array of segment objects (index, startPage, endPage, ...)
let planJson = try doc.planSplitByBookmarks(optionsJson: #"{"level": 1}"#)
print(planJson)
WASM
import { planSplitByBookmarks } from "pdf-oxide-wasm";
// level 1 = top-level bookmarks; returns an array of segment objects
const segments = planSplitByBookmarks(bytes, null, false, 1, true);
for (const seg of segments) {
console.log(`#${seg.index}: ${seg.startPage}-${seg.endPage} => ${seg.fileStem}.pdf`);
}
Java
import fyi.oxide.pdf.Pdf;
import java.nio.file.*;
byte[] src = Files.readAllBytes(Path.of("manual.pdf"));
// level 1 = top-level bookmarks; returns the number of segments the split would produce
int segmentCount = Pdf.planSplitByBookmarksCount(src, 1);
System.out.println(segmentCount + " segments");
Ruby
require 'pdf_oxide'
src = File.binread('manual.pdf')
# level 1 = top-level bookmarks; returns the number of segments the split would produce
segment_count = PdfOxide::Pdf.plan_split_by_bookmarks_count(src, 1)
puts "#{segment_count} segments"
C++
auto doc = pdf_oxide::Document::open("manual.pdf");
// Returns a JSON array of segment objects (index, start_page, end_page, ...)
std::string planJson = doc.plan_split_by_bookmarks(R"({"level": 1})");
std::cout << planJson << "\n";
Dart
final doc = PdfDocument.open('manual.pdf');
// Returns a JSON array of segment objects (index, startPage, endPage, ...)
final planJson = doc.planSplitByBookmarks('{"level": 1}');
print(planJson);
R
doc <- pdf_open("manual.pdf")
# Returns a JSON array of segment objects (index, start_page, end_page, ...)
plan_json <- pdf_plan_split_by_bookmarks(doc, '{"level": 1}')
cat(plan_json, "\n")
Julia
doc = open_document("manual.pdf")
# Returns a JSON array of segment objects (index, start_page, end_page, ...)
plan_json = plan_split_by_bookmarks(doc, """{"level": 1}""")
println(plan_json)
Zig
const a = std.heap.page_allocator;
var doc = try pdf_oxide.Document.open("manual.pdf");
defer doc.deinit();
// Returns a JSON array of segment objects (index, start_page, end_page, ...)
const plan_json = try doc.planSplitByBookmarks(a, "{\"level\": 1}");
defer a.free(plan_json);
std.debug.print("{s}\n", .{plan_json});
Objective-C
POXDocument *doc = [POXDocument openPath:@"manual.pdf" error:&err];
// Returns a JSON array of segment objects (index, start_page, end_page, ...)
NSString *planJson = [doc planSplitByBookmarks:@"{\"level\": 1}" error:&err];
NSLog(@"%@", planJson);
Elixir
{:ok, doc} = PdfOxide.open("manual.pdf")
# Returns a JSON array of segment objects (index, start_page, end_page, ...)
{:ok, plan_json} = PdfOxide.plan_split_by_bookmarks(doc, ~s({"level": 1}))
IO.puts(plan_json)
각 세그먼트에는 다음 정보가 포함됩니다: index(1부터 시작하는 순서 번호), start_page(포함, 0부터), end_page(제외, 0부터 — 범위는 start_page..end_page), title(소스 북마크 제목, 앞부분 프론트 매터 세그먼트는 null), file_stem(중복 제거된 파일 시스템 안전 이름, 확장자 없음), page_label.
분할 옵션
| 옵션 | 기본값 | 설명 |
|---|---|---|
title_prefix |
없음 | 이 접두사로 시작하는 제목의 북마크에서만 분할 |
ignore_case |
false |
접두사 매칭 시 대소문자 무시 |
level |
1(최상위) |
0 = 모든 깊이, 1 = 최상위만, n = 깊이 n까지 |
include_front_matter |
true |
첫 번째 분할 지점 이전의 페이지를 앞부분 세그먼트로 포함 |
계획 수립 후 추출
계획은 단순한 페이지 범위이므로, 각 세그먼트를 경계를 다시 계산할 필요 없이 곧바로 인메모리 추출기에 전달할 수 있습니다.
import pdf_oxide
from pdf_oxide import PdfDocument
with open("manual.pdf", "rb") as f:
src = f.read()
doc = PdfDocument.from_bytes(src)
for seg in pdf_oxide.plan_split_by_bookmarks(src, level=1):
pages = list(range(seg["start_page"], seg["end_page"]))
chunk = doc.extract_pages_to_bytes(pages)
with open(f"{seg['file_stem']}.pdf", "wb") as out:
out.write(chunk)
바인딩 지원 현황.
plan_split_by_bookmarks는 Python(모듈 수준 함수pdf_oxide.plan_split_by_bookmarks), Rust(pdf_oxide::split_bookmarks::plan_split_by_bookmarks), Swift(planSplitByBookmarks), WASM(planSplitByBookmarks), C ABI(pdf_document_plan_split_by_bookmarks)에서 공개되어 있습니다. 문서에 개요가 없으면 오류가 발생합니다(Python에서는RuntimeError). 이 경우 페이지 단위 또는 청크 단위 분할을 사용하세요.
자주 묻는 질문
extract_pages와 extract_pages_to_bytes의 차이는 무엇인가요?
extract_pages(pages, output)는 결과를 파일 경로에 씁니다. extract_pages_to_bytes(pages)는 새 PDF를 메모리 내 바이트로 반환합니다. 두 함수 모두 0부터 시작하는 페이지 인덱스를 받으며 원본 문서는 수정하지 않습니다. 출력을 디스크에 저장하지 않고 스트리밍하거나 전달할 때는 인메모리 버전을 선택하세요.
plan_split_by_bookmarks가 PDF 파일을 만드나요?
아니요. 세그먼트 메타데이터(페이지 범위, 제목, 파일 이름)만 반환하는 순수하고 가벼운 플래너입니다. 실제로 청크를 생성하려면 extract_pages_to_bytes와 함께 사용하거나, 세그먼트와 바이트 쌍을 반환하는 일회성 헬퍼 split_by_bookmarks(Python/Rust/WASM)를 사용하세요.
챕터별로 PDF를 분할하려면 어떻게 하나요?
PDF에 개요가 있다면 plan_split_by_bookmarks(src, level=1)을 호출해 최상위 북마크마다 세그먼트를 하나씩 받고, 각 세그먼트의 start_page..end_page 범위를 extract_pages_to_bytes로 추출하세요. level=0으로 설정하면 모든 개요 깊이에서 분할합니다.
왜 분할이 이렇게 빠른가요? 분할은 PDF Oxide의 순수 Rust 코어에서 PDF 객체 수준으로 동작합니다. 평균 0.8ms 추출 속도와 100% 통과율을 기록한 동일한 엔진입니다. 분할 계획은 개요와 페이지 수만 참조하므로 큰 문서에서도 사실상 즉각적으로 완료됩니다.
관련 페이지
- 페이지 작업 — 회전, 자르기, 순서 변경
- 일괄 처리 — 병렬 처리 패턴
- Python 시작하기 — 설치 및 기초