Начало работы с PDF Oxide (Swift)
PDF Oxide — самая быстрая PDF-библиотека со встроенным извлечением текста: 0.8 мс в среднем, 100% успешных проверок на 3830 PDF. Привязка для Swift, появившаяся в v0.3.69, оборачивает ядро на Rust через C ABI: дескрипторы принадлежат классам (освобождаются в deinit), C-буферы копируются в Swift String/[UInt8], а коды ошибок выбрасываются как PdfOxideError.
Установка
Привязка линкуется с cdylib, собранной с набором фич по умолчанию. Соберите нативную библиотеку, затем укажите SwiftPM путь к заголовкам и библиотеке:
# 1. собрать нативную библиотеку (набор фич для поставляемой привязки)
cargo build --release --lib --features ocr,rendering,signatures,barcodes,tsa-client,system-fonts
# 2. тесты + запуск примера (Package.swift читает PDF_OXIDE_INCLUDE_DIR / _LIB_DIR)
cd swift
export PDF_OXIDE_INCLUDE_DIR="$PWD/../include"
export PDF_OXIDE_LIB_DIR="$PWD/../target/release"
DYLD_LIBRARY_PATH="$PDF_OXIDE_LIB_DIR" swift test
DYLD_LIBRARY_PATH="$PDF_OXIDE_LIB_DIR" swift run basic_extraction
Быстрый старт
Соберите PDF из Markdown, откройте его из полученных байтов и извлеките текст. Весь этот цикл проходит без каких-либо внешних файлов:
import PdfOxide
let pdf = try Pdf.fromMarkdown("# Hello pdf_oxide\n\nThis is a **Swift** binding.\n")
let doc = try Document.openFromBytes(try pdf.toBytes())
print("pages: \(try doc.pageCount())")
print("version: \(try doc.version())")
print(try doc.extractText(0))
Чтобы открыть файл с диска, используйте Document.open(_:):
import PdfOxide
let doc = try Document.open("research-paper.pdf")
print("Pages: \(try doc.pageCount())")
print("Version: \(try doc.version())") // например, 1.7
Извлечение текста
extractText(_:) возвращает текст одной страницы (нумерация с нуля). Пройдитесь циклом по pageCount(), чтобы прочитать весь документ:
import PdfOxide
let doc = try Document.open("book.pdf")
for i in 0..<(try doc.pageCount()) {
print("--- Page \(i + 1) ---")
print(try doc.extractText(i))
}
toPlainText(_:) даёт упрощённый вариант без сохранения раскладки, а методы *All() извлекают сразу все страницы:
let doc = try Document.open("report.pdf")
let plain = try doc.toPlainText(0) // одна страница, без раскладки
let everything = try doc.toPlainTextAll() // все страницы, объединённые
Слова и символы
extractWords(_:) возвращает [Word] с ограничивающим прямоугольником и метаданными шрифта для каждого слова. extractChars(_:) возвращает [Char] с позиционированием каждого символа:
import PdfOxide
let doc = try Document.open("paper.pdf")
let words = try doc.extractWords(0)
for word in words.prefix(10) {
print("'\(word.text)' at (\(word.bbox.x), \(word.bbox.y)) "
+ "font=\(word.fontName) size=\(word.fontSize) bold=\(word.bold)")
}
let chars = try doc.extractChars(0)
for ch in chars.prefix(10) {
let scalar = Unicode.Scalar(ch.character).map(String.init) ?? "?"
print("'\(scalar)' size=\(ch.fontSize) font=\(ch.fontName)")
}
Поля Word: text (String), bbox (Bbox), fontName (String), fontSize (Double), bold (Bool). Поля Char: character (кодовая точка UInt32), bbox, fontName, fontSize. Bbox предоставляет x, y, width и height в виде Double.
Текст можно также получать построчно через extractTextLines(_:), который возвращает [TextLine] (text, bbox, wordCount):
let lines = try doc.extractTextLines(0)
for line in lines {
print("\(line.wordCount) words: \(line.text)")
}
Конвертация в Markdown и HTML
Конвертируйте одну страницу или весь документ в Markdown или HTML:
import PdfOxide
let doc = try Document.open("paper.pdf")
let md = try doc.toMarkdown(0) // одна страница в Markdown
let mdAll = try doc.toMarkdownAll() // весь документ в Markdown
let html = try doc.toHtml(0) // одна страница в HTML
let htmlAll = try doc.toHtmlAll() // весь документ в HTML
print(mdAll)
Поиск
search(_:_:_:) ищет по одной странице; searchAll(_:_:) ищет по всему документу. Оба метода принимают искомую строку и флаг caseSensitive и возвращают [SearchResult] (text, page, bbox):
import PdfOxide
let doc = try Document.open("manual.pdf")
// Поиск по одной странице (страница 0, без учёта регистра)
let hits = try doc.search(0, "configuration", false)
for hit in hits {
print("page \(hit.page): '\(hit.text)' at (\(hit.bbox.x), \(hit.bbox.y))")
}
// Поиск по всему документу
let allHits = try doc.searchAll("configuration", false)
print("\(allHits.count) total matches")
Создание PDF
Тип Pdf предоставляет фабричные методы, которые собирают документ из исходного формата. Сохраните его на диск через save(_:) или получите сырые байты через toBytes():
import PdfOxide
try Pdf.fromMarkdown("# Hello World\n\nThis is a PDF.").save("output.pdf")
try Pdf.fromHtml("<h1>Invoice</h1><p>Amount: $42</p>").save("invoice.pdf")
try Pdf.fromText("Plain text content.").save("notes.pdf")
let bytes = try Pdf.fromMarkdown("# In-memory\n\nbody\n").toBytes()
print("produced \(bytes.count) bytes")
Обработка ошибок
Каждый вызов, способный завершиться неудачей, выбрасывает PdfOxideError, который содержит имя сбойной операции и базовый код ошибки C ABI:
import PdfOxide
do {
let doc = try Document.open("document.pdf")
print(try doc.extractText(0))
} catch let error as PdfOxideError {
print("PDF error: \(error)") // например, "PdfOxideError: open failed (error code 1)"
}
Дальнейшие шаги
- Начало работы с Rust – использование PDF Oxide из Rust
- Начало работы с Python – использование PDF Oxide из Python
- Извлечение текста – подробные параметры и рецепты извлечения
- Создание PDF – продвинутое создание с метаданными и шифрованием
- Редактирование – изменение существующих PDF, аннотации и поля форм