Извлечение текста
PDF Oxide предоставляет несколько уровней извлечения текста: полный текст страницы, стилизованные span-ы с метаданными шрифта и отдельные символы с точным позиционированием. Используйте extract_text() для быстрого получения содержимого, extract_spans() когда нужны данные о шрифте и позиции, и extract_chars() для посимвольного анализа — например, в собственных движках разметки или при постобработке OCR.
Для тегированных PDF извлечение текста автоматически следует дереву структуры документа для корректного порядка чтения. Для нетегированных PDF используется порядок содержимого страницы с интеллектуальным определением переносов строк — включая защиту одноколоночного макета, предотвращающую фрагментацию основного текста в документах в стиле RFC и диссертаций.
Поддержка порядка чтения
Конвейер определения порядка чтения обеспечивает корректный вывод для различных письменностей и макетов:
- Latin — стандартный порядок слева направо, сверху вниз с определением колонок.
- Arabic — обращение предварительно оформленных span-ов (Pass 0) располагает символы в логическом порядке чтения вместо визуального.
- CJK — пространственный детектор таблиц сохраняет колонки с метками rowspan; 3-точечная квантизация по оси Y не даёт табличному содержимому перемешиваться с текстом.
- Повёрнутые / сгенерированные dvips PDF — отсев выбросов на основе медианы при определении колонок обрабатывает вырожденные CTM-координаты.
- Многоколоночные научные статьи — одноколоночная защита XYCut устраняет фрагментацию; построчная сортировка span-ов обрабатывает табличное содержимое внутри текстовых блоков.
Сегментация слов и строк
extract_words() и extract_text_lines() принимают необязательные именованные параметры для настройки порогов разбивки на слова и строки:
| Параметр | По умолчанию | Описание |
|---|---|---|
word_gap_threshold |
адаптивный | Минимальный горизонтальный промежуток (в пунктах) между соседними символами, считающийся границей слова |
line_gap_threshold |
адаптивный | Минимальный вертикальный промежуток между базовыми линиями, считающийся переносом строки |
profile |
"auto" |
Одно из значений "auto", "dense", "standard", "sparse" — выбирает предустановку для разных макетов |
Адаптивные параметры вычисляются на основе метрик шрифтов страницы. Используйте page_layout_params() для просмотра вычисленных значений и ExtractionProfile для создания собственного профиля.
Настройка только для Python:
word_gap_threshold,line_gap_threshold,profileиpage_layout_params()доступны в привязке Python. Привязки Node.js, JavaScript, Go, C# и WASM предоставляютextractWords(pageIndex)/extractTextLines(pageIndex)с адаптивными значениями по умолчанию без именованных параметров. Для настройки из этих языков используйте Rust API ниже.
Python
from pdf_oxide import PdfDocument, ExtractionProfile
doc = PdfDocument("receipt.pdf")
params = doc.page_layout_params(0)
print(params.word_gap_threshold, params.line_gap_threshold)
words = doc.extract_words(0, word_gap_threshold=2.5, profile="dense")
lines = doc.extract_text_lines(0, profile=ExtractionProfile.DENSE)
Node.js
const { PdfDocument } = require("pdf-oxide");
const doc = new PdfDocument("receipt.pdf");
const words = doc.extractWords(0); // adaptive defaults
const lines = doc.extractTextLines(0);
doc.close();
JavaScript
const { PdfDocument } = require("pdf-oxide");
const doc = new PdfDocument("receipt.pdf");
const words = doc.extractWords(0);
const lines = doc.extractTextLines(0);
doc.close();
TypeScript
import { PdfDocument } from "pdf-oxide";
const doc: PdfDocument = new PdfDocument("receipt.pdf");
const words = doc.extractWords(0);
const lines = doc.extractTextLines(0);
doc.close();
Rust
use pdf_oxide::{PdfDocument, ExtractionProfile};
let mut doc = PdfDocument::open("receipt.pdf")?;
let params = doc.page_layout_params(0)?;
println!("{} {}", params.word_gap_threshold, params.line_gap_threshold);
let words = doc.extract_words_with_config(0, /* word_gap_threshold */ Some(2.5), ExtractionProfile::Dense)?;
let lines = doc.extract_text_lines_with_profile(0, ExtractionProfile::Dense)?;
Go
words, _ := doc.ExtractWords(0) // adaptive defaults
lines, _ := doc.ExtractTextLines(0)
C#
var words = doc.ExtractWords(0); // adaptive defaults
var lines = doc.ExtractTextLines(0);
WASM
const doc = new WasmPdfDocument(bytes);
const words = doc.extractWords(0);
const lines = doc.extractTextLines(0);
Java
try (PdfDocument doc = PdfDocument.open(Path.of("receipt.pdf"))) {
List<TextWord> words = doc.page(0).words(); // adaptive defaults
List<TextLine> lines = doc.page(0).lines();
}
C++
auto doc = pdf_oxide::Document::open("receipt.pdf");
auto words = doc.extract_words(0); // adaptive defaults
auto lines = doc.extract_text_lines(0);
Swift
let doc = try Document.open("receipt.pdf")
let words = try doc.extractWords(0) // adaptive defaults
let lines = try doc.extractTextLines(0)
Kotlin
PdfDocument.open(Path.of("receipt.pdf")).use { doc ->
val words = doc.page(0).words() // adaptive defaults
val lines = doc.page(0).lines()
}
Dart
final doc = PdfDocument.open('receipt.pdf');
final words = doc.extractWords(0); // adaptive defaults
final lines = doc.extractTextLines(0);
R
doc <- pdf_open("receipt.pdf")
words <- pdf_extract_words(doc, 0) # adaptive defaults
lines <- pdf_extract_text_lines(doc, 0)
Julia
doc = open_document("receipt.pdf")
words = extract_words(doc, 0) # adaptive defaults
lines = extract_text_lines(doc, 0)
Zig
var doc = try pdf_oxide.Document.open("receipt.pdf");
const words = try doc.extractWords(a, 0); // adaptive defaults
const lines = try doc.extractTextLines(a, 0);
Scala
Using.resource(PdfDocument.open("receipt.pdf")) { doc =>
val words = doc.page(0).wordsSeq // adaptive defaults
val lines = doc.page(0).linesSeq
}
Clojure
(with-open [doc (pdf/open "receipt.pdf")]
(pdf/words (pdf/page doc 0)) ; adaptive defaults
(pdf/lines (pdf/page doc 0)))
Objective-C
POXDocument *doc = [POXDocument openPath:@"receipt.pdf" error:&err];
NSArray<POXWord*> *words = [doc extractWords:0 error:&err]; // adaptive defaults
NSArray<POXTextLine*> *lines = [doc extractTextLines:0 error:&err];
Elixir
{:ok, doc} = PdfOxide.open("receipt.pdf")
{:ok, words} = PdfOxide.extract_words(doc, 0) # adaptive defaults
{:ok, lines} = PdfOxide.extract_text_lines(doc, 0)
Быстрый пример
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("report.pdf")
text = doc.extract_text(0)
print(text)
Node.js
const { PdfDocument } = require("pdf-oxide");
const doc = new PdfDocument("report.pdf");
const text = doc.extractText(0);
console.log(text);
Go
import pdfoxide "github.com/yfedoseev/pdf_oxide/go"
doc, _ := pdfoxide.Open("report.pdf")
defer doc.Close()
text, _ := doc.ExtractText(0)
fmt.Println(text)
C#
using PdfOxide.Core;
using var doc = PdfDocument.Open("report.pdf");
string text = doc.ExtractText(0);
Console.WriteLine(text);
WASM
const doc = new WasmPdfDocument(bytes);
const text = doc.extractText(0);
console.log(text);
Rust
use pdf_oxide::PdfDocument;
let mut doc = PdfDocument::open("report.pdf")?;
let text = doc.extract_text(0)?;
println!("{}", text);
Java
import fyi.oxide.pdf.*;
import java.nio.file.Path;
try (PdfDocument doc = PdfDocument.open(Path.of("report.pdf"))) {
String text = doc.extractText(0);
System.out.println(text);
}
PHP
use PdfOxide\PdfDocument;
$doc = PdfDocument::open('report.pdf');
$text = $doc->extractText(0);
echo $text;
$doc->close();
Ruby
require 'pdf_oxide'
PdfOxide::PdfDocument.open('report.pdf') do |doc|
text = doc.extract_text(0)
puts text
end
C++
#include <pdf_oxide/pdf_oxide.hpp>
auto doc = pdf_oxide::Document::open("report.pdf");
auto text = doc.extract_text(0);
std::cout << text << "\n";
Swift
import PdfOxide
let doc = try Document.open("report.pdf")
let text = try doc.extractText(0)
print(text)
Kotlin
import fyi.oxide.pdf.*
PdfDocument.open(java.nio.file.Path.of("report.pdf")).use { doc ->
val text = doc.extractText(0)
println(text)
}
Dart
import 'package:pdf_oxide/pdf_oxide.dart';
final doc = PdfDocument.open('report.pdf');
final text = doc.extractText(0);
print(text);
R
library(pdfoxide)
doc <- pdf_open("report.pdf")
text <- pdf_extract_text(doc, 0)
cat(text)
Julia
using PdfOxide
doc = open_document("report.pdf")
text = extract_text(doc, 0)
println(text)
Zig
const pdf_oxide = @import("pdf_oxide");
var doc = try pdf_oxide.Document.open("report.pdf");
const text = try doc.extractText(a, 0);
std.debug.print("{s}\n", .{text});
Scala
import fyi.oxide.pdf.PdfDocument
import scala.util.Using
Using.resource(PdfDocument.open("report.pdf")) { doc =>
val text = doc.extractText(0)
println(text)
}
Clojure
(require '[pdf-oxide.core :as pdf])
(with-open [doc (pdf/open "report.pdf")]
(println (pdf/extract-text doc 0)))
Objective-C
#import "POXPdfOxide.h"
NSError *err = nil;
POXDocument *doc = [POXDocument openPath:@"report.pdf" error:&err];
NSString *text = [doc extractText:0 error:&err];
NSLog(@"%@", text);
Elixir
{:ok, doc} = PdfOxide.open("report.pdf")
{:ok, text} = PdfOxide.extract_text(doc, 0)
IO.puts(text)
Справочник API
extract_text(page_index) -> str
Извлекает весь текст страницы в виде единой строки. Автоматически обнаруживает тегированные PDF и использует дерево структуры для определения порядка чтения, если оно доступно. Вставляет переносы строк и пробелы на основе вертикальных и горизонтальных промежутков между span-ами.
| Параметр | Тип | Описание |
|---|---|---|
page_index |
int / usize |
Индекс страницы (начиная с нуля) |
Возвращает: Полное текстовое содержимое страницы.
Python
doc = PdfDocument("report.pdf")
for i in range(doc.page_count()):
text = doc.extract_text(i)
print(f"--- Page {i + 1} ---")
print(text)
Node.js
const doc = new PdfDocument("report.pdf");
for (let i = 0; i < doc.getPageCount(); i++) {
const text = doc.extractText(i);
console.log(`--- Page ${i + 1} ---`);
console.log(text);
}
Go
doc, _ := pdfoxide.Open("report.pdf")
defer doc.Close()
count, _ := doc.PageCount()
for i := 0; i < count; i++ {
text, _ := doc.ExtractText(i)
fmt.Printf("--- Page %d ---\n", i+1)
fmt.Println(text)
}
C#
using var doc = PdfDocument.Open("report.pdf");
for (int i = 0; i < doc.PageCount; i++)
{
string text = doc.ExtractText(i);
Console.WriteLine($"--- Page {i + 1} ---");
Console.WriteLine(text);
}
WASM
const doc = new WasmPdfDocument(bytes);
for (let i = 0; i < doc.pageCount(); i++) {
const text = doc.extractText(i);
console.log(`--- Page ${i + 1} ---`);
console.log(text);
}
Rust
let mut doc = PdfDocument::open("report.pdf")?;
let page_count = doc.page_count()?;
for i in 0..page_count {
let text = doc.extract_text(i)?;
println!("--- Page {} ---", i + 1);
println!("{}", text);
}
Java
try (PdfDocument doc = PdfDocument.open(Path.of("report.pdf"))) {
int n = doc.pageCount();
for (int i = 0; i < n; i++) {
System.out.println("--- Page " + (i + 1) + " ---");
System.out.println(doc.extractText(i));
}
}
PHP
$doc = PdfDocument::open('report.pdf');
$n = $doc->pageCount();
for ($i = 0; $i < $n; $i++) {
echo "--- Page " . ($i + 1) . " ---\n";
echo $doc->extractText($i);
}
$doc->close();
Ruby
PdfOxide::PdfDocument.open('report.pdf') do |doc|
(0...doc.page_count).each do |i|
puts "--- Page #{i + 1} ---"
puts doc.extract_text(i)
end
end
C++
auto doc = pdf_oxide::Document::open("report.pdf");
int n = doc.page_count();
for (int i = 0; i < n; i++) {
std::cout << "--- Page " << (i + 1) << " ---\n";
std::cout << doc.extract_text(i) << "\n";
}
Swift
let doc = try Document.open("report.pdf")
let n = try doc.pageCount()
for i in 0..<n {
print("--- Page \(i + 1) ---")
print(try doc.extractText(i))
}
Kotlin
PdfDocument.open(java.nio.file.Path.of("report.pdf")).use { doc ->
for (i in 0 until doc.pageCount()) {
println("--- Page ${i + 1} ---")
println(doc.extractText(i))
}
}
Dart
final doc = PdfDocument.open('report.pdf');
for (var i = 0; i < doc.pageCount; i++) {
print('--- Page ${i + 1} ---');
print(doc.extractText(i));
}
R
doc <- pdf_open("report.pdf")
for (i in seq_len(pdf_page_count(doc)) - 1) {
cat(sprintf("--- Page %d ---\n", i + 1))
cat(pdf_extract_text(doc, i))
}
Julia
doc = open_document("report.pdf")
for i in 0:(page_count(doc) - 1)
println("--- Page $(i + 1) ---")
println(extract_text(doc, i))
end
Zig
var doc = try pdf_oxide.Document.open("report.pdf");
const n = try doc.pageCount();
var i: usize = 0;
while (i < n) : (i += 1) {
std.debug.print("--- Page {d} ---\n", .{i + 1});
const text = try doc.extractText(a, i);
std.debug.print("{s}\n", .{text});
}
Scala
Using.resource(PdfDocument.open("report.pdf")) { doc =>
for (i <- 0 until doc.pageCount()) {
println(s"--- Page ${i + 1} ---")
println(doc.extractText(i))
}
}
Clojure
(with-open [doc (pdf/open "report.pdf")]
(doseq [i (range (pdf/page-count doc))]
(println (str "--- Page " (inc i) " ---"))
(println (pdf/extract-text doc i))))
Objective-C
POXDocument *doc = [POXDocument openPath:@"report.pdf" error:&err];
NSInteger n = [doc pageCountError:&err];
for (NSInteger i = 0; i < n; i++) {
NSLog(@"--- Page %ld ---", (long)(i + 1));
NSLog(@"%@", [doc extractText:i error:&err]);
}
Elixir
{:ok, doc} = PdfOxide.open("report.pdf")
{:ok, n} = PdfOxide.page_count(doc)
Enum.each(0..(n - 1), fn i ->
IO.puts("--- Page #{i + 1} ---")
{:ok, text} = PdfOxide.extract_text(doc, i)
IO.puts(text)
end)
extract_spans(page_index) -> list[TextSpan]
Извлекает текст в виде span-ов — непрерывных фрагментов текста с одинаковым шрифтом и стилем. Каждый span содержит текстовое содержимое, ограничивающий прямоугольник, название шрифта, размер шрифта, насыщенность, флаг курсива и цвет. Это рекомендуемый подход для большинства задач извлечения, требующих информации о макете или шрифте.
| Параметр | Тип | Описание |
|---|---|---|
page_index |
int / usize |
Индекс страницы (начиная с нуля) |
Возвращает: Список/вектор объектов TextSpan.
Поля TextSpan
| Поле | Тип | Описание |
|---|---|---|
text |
str |
Текстовое содержимое span-а |
bbox |
Rect |
Ограничивающий прямоугольник (x, y, ширина, высота) |
font_name |
str |
Название/семейство шрифта (например, “Helvetica”, “TimesNewRoman”) |
font_size |
f32 |
Размер шрифта в пунктах |
font_weight |
FontWeight |
Насыщенность: Normal, Bold, Light, SemiBold и др. |
is_italic |
bool |
Является ли span курсивным |
color |
Color |
RGB-цвет (r, g, b) со значениями 0,0–1,0 |
mcid |
Option<u32> |
Идентификатор помеченного содержимого для тегированных PDF |
sequence |
usize |
Порядок извлечения (используется для разрешения конфликтов при сортировке по Y) |
is_monospace |
bool |
Является ли шрифт моноширинным (Courier, Consolas и др.) |
char_widths |
list[float] |
Ширина продвижения для каждого глифа (для точных ограничивающих прямоугольников) |
char_spacing |
f32 |
Межсимвольный интервал (параметр Tc) |
word_spacing |
f32 |
Межсловный интервал (параметр Tw) |
horizontal_scaling |
f32 |
Горизонтальное масштабирование в процентах (Tz, по умолчанию 100,0) |
Rust
let mut doc = PdfDocument::open("paper.pdf")?;
let spans = doc.extract_spans(0)?;
for span in &spans {
println!(
"'{}' at ({:.1}, {:.1}) font={} size={:.1}pt bold={} italic={}",
span.text,
span.bbox.x, span.bbox.y,
span.font_name,
span.font_size,
span.font_weight == FontWeight::Bold,
span.is_italic,
);
}
extract_spans_with_config(page_index, config) -> Vec<TextSpan>
Извлекает span-ы с пользовательской конфигурацией слияния. Используйте этот метод, когда поведение слияния по умолчанию даёт неверные границы слов для вашего документа.
| Параметр | Тип | Описание |
|---|---|---|
page_index |
usize |
Индекс страницы (начиная с нуля) |
config |
SpanMergingConfig |
Конфигурация параметров извлечения |
Rust
use pdf_oxide::extractors::SpanMergingConfig;
let mut doc = PdfDocument::open("report.pdf")?;
let config = SpanMergingConfig::adaptive();
let spans = doc.extract_spans_with_config(0, config)?;
extract_chars(page_index) -> list[TextChar]
Извлекает отдельные символы с точными ограничивающими прямоугольниками, метаданными шрифта и свойствами преобразования. Это низкоуровневый API — для большинства задач предпочтительнее использовать extract_text() или extract_spans(). Извлечение символов работает на 30–50% быстрее извлечения span-ов, так как пропускает этап группировки и объединения текста.
| Параметр | Тип | Описание |
|---|---|---|
page_index |
int / usize |
Индекс страницы (начиная с нуля) |
Возвращает: Список/вектор объектов TextChar.
Поля TextChar
| Поле | Тип | Описание |
|---|---|---|
char |
char |
Символ |
bbox |
Rect |
Ограничивающий прямоугольник (x, y, ширина, высота) |
font_name |
str |
Название/семейство шрифта |
font_size |
f32 |
Размер шрифта в пунктах |
font_weight |
FontWeight |
Насыщенность (Normal, Bold и др.) |
is_italic |
bool |
Флаг курсива |
color |
Color |
RGB-цвет (от 0,0 до 1,0 по каждому каналу) |
mcid |
Option<u32> |
Идентификатор помеченного содержимого |
origin_x |
f32 |
Координата X начала базовой линии |
origin_y |
f32 |
Координата Y начала базовой линии |
rotation_degrees |
f32 |
Угол поворота текста (0–360, по часовой стрелке) |
advance_width |
f32 |
Горизонтальное расстояние до следующей позиции символа |
matrix |
[f32; 6] |
Полная матрица преобразования [a, b, c, d, e, f] |
Python
doc = PdfDocument("report.pdf")
chars = doc.extract_chars(0)
for ch in chars:
print(f"'{ch.char}' at ({ch.bbox[0]:.1f}, {ch.bbox[1]:.1f}) "
f"font={ch.font_name} size={ch.font_size:.1f}")
<!-- Node.js: extractChars not yet in binding (js/src/index.ts) -->
Go
doc, _ := pdfoxide.Open("report.pdf")
defer doc.Close()
chars, _ := doc.ExtractChars(0)
for _, ch := range chars {
fmt.Printf("'%c' at (%.1f, %.1f) font=%s size=%.1f\n",
ch.Char, ch.X, ch.Y, ch.FontName, ch.FontSize)
}
C#
using var doc = PdfDocument.Open("report.pdf");
var chars = doc.ExtractChars(0);
foreach (var ch in chars)
{
Console.WriteLine($"'{ch.Char}' at ({ch.X:F1}, {ch.Y:F1}) {ch.W:F1}x{ch.H:F1}");
}
WASM
const doc = new WasmPdfDocument(bytes);
const chars = doc.extractChars(0);
for (const ch of chars) {
console.log(`'${ch.char}' at (${ch.bbox[0].toFixed(1)}, ${ch.bbox[1].toFixed(1)}) font=${ch.fontName} size=${ch.fontSize.toFixed(1)}`);
}
Rust
let mut doc = PdfDocument::open("report.pdf")?;
let chars = doc.extract_chars(0)?;
for ch in &chars {
println!(
"'{}' origin=({:.1}, {:.1}) rotation={:.0} advance={:.1}",
ch.char, ch.origin_x, ch.origin_y,
ch.rotation_degrees, ch.advance_width,
);
}
C++
auto doc = pdf_oxide::Document::open("report.pdf");
auto chars = doc.extract_chars(0);
for (const auto& ch : chars) {
std::printf("U+%04X at (%.1f, %.1f) font=%s size=%.1f\n",
ch.character, ch.bbox.x, ch.bbox.y,
ch.font_name.c_str(), ch.font_size);
}
Swift
let doc = try Document.open("report.pdf")
let chars = try doc.extractChars(0)
for ch in chars {
let scalar = String(UnicodeScalar(ch.character)!)
print("'\(scalar)' at (\(ch.bbox.x), \(ch.bbox.y)) font=\(ch.fontName) size=\(ch.fontSize)")
}
Dart
final doc = PdfDocument.open('report.pdf');
final chars = doc.extractChars(0);
for (final ch in chars) {
final glyph = String.fromCharCode(ch.character);
print("'$glyph' at (${ch.bbox.x}, ${ch.bbox.y}) font=${ch.fontName} size=${ch.fontSize}");
}
R
doc <- pdf_open("report.pdf")
chars <- pdf_extract_chars(doc, 0)
for (ch in chars) {
cat(sprintf("U+%04X at (%.1f, %.1f) font=%s size=%.1f\n",
ch$character, ch$bbox$x, ch$bbox$y, ch$font_name, ch$font_size))
}
Julia
doc = open_document("report.pdf")
chars = extract_chars(doc, 0)
for ch in chars
glyph = Char(ch.character)
println("'$glyph' at ($(ch.bbox.x), $(ch.bbox.y)) font=$(ch.font_name) size=$(ch.font_size)")
end
Zig
var doc = try pdf_oxide.Document.open("report.pdf");
const chars = try doc.extractChars(a, 0);
for (chars) |ch| {
std.debug.print("U+{X:0>4} at ({d:.1}, {d:.1}) font={s} size={d:.1}\n",
.{ ch.character, ch.bbox.x, ch.bbox.y, ch.fontName, ch.fontSize });
}
Objective-C
POXDocument *doc = [POXDocument openPath:@"report.pdf" error:&err];
NSArray<POXChar*> *chars = [doc extractChars:0 error:&err];
for (POXChar *ch in chars) {
NSLog(@"U+%04X at (%.1f, %.1f) font=%@ size=%.1f",
ch.character, ch.bbox.x, ch.bbox.y, ch.fontName, ch.fontSize);
}
Elixir
{:ok, doc} = PdfOxide.open("report.pdf")
{:ok, chars} = PdfOxide.extract_chars(doc, 0)
Enum.each(chars, fn ch ->
glyph = <<ch.character::utf8>>
IO.puts("'#{glyph}' at (#{ch.bbox.x}, #{ch.bbox.y}) font=#{ch.font_name} size=#{ch.font_size}")
end)
extract_page_text(page_index) -> PageText
Получает span-ы, символы и размеры страницы за один проход извлечения. Эффективнее, чем отдельные вызовы extract_spans() + extract_chars(), поскольку поток содержимого страницы разбирается лишь однажды.
| Параметр | Тип | Описание |
|---|---|---|
page_index |
int / usize |
Индекс страницы (начиная с нуля) |
Возвращает: Объект PageText (dict в Python / object в JS) с полями: spans, chars, page_width, page_height, text.
Python
doc = PdfDocument("report.pdf")
result = doc.extract_page_text(0)
# result is a dict with: spans, chars, page_width, page_height, text
for span in result["spans"]:
print(f"'{span.text}' font={span.font_name} size={span.font_size}")
<!-- Node.js: extractPageText not yet in binding (js/src/index.ts) --> <!-- Go: ExtractPageText not yet in binding (go/pdf_oxide.go) --> <!-- C#: ExtractPageText not yet in binding (csharp/PdfOxide/Core/PdfDocument.cs) -->
WASM
const result = doc.extractPageText(0);
// result has: spans, chars, pageWidth, pageHeight, text
for (const span of result.spans) {
console.log(`'${span.text}' font=${span.fontName} size=${span.fontSize}`);
}
Rust
let mut doc = PdfDocument::open("report.pdf")?;
let result = doc.extract_page_text(0)?;
println!("Page is {}x{} pt", result.page_width, result.page_height);
for span in &result.spans {
println!("'{}' font={} size={:.1}", span.text, span.font_name, span.font_size);
}
Порядок чтения с учётом колонок
Для многоколоночных PDF (научные статьи, газеты) используйте режим чтения с учётом колонок, чтобы обрабатывать каждую колонку отдельно, а не считывать текст поперёк колонок:
Python
# Default: top-to-bottom (reads across columns)
spans = doc.extract_spans(0)
# Column-aware: reads each column separately
spans = doc.extract_spans(0, reading_order="column_aware")
<!-- Node.js: extractSpans not yet in binding (js/src/index.ts) --> <!-- Go: ExtractSpans not yet in binding (go/pdf_oxide.go) --> <!-- C#: ExtractSpans not yet in binding (csharp/PdfOxide/Core/PdfDocument.cs) -->
WASM
const spans = doc.extractSpans(0, undefined, "column_aware");
Rust
use pdf_oxide::extractors::ReadingOrder;
let spans = doc.extract_spans_with_reading_order(0, ReadingOrder::ColumnAware)?;
to_plain_text(page_index, options) -> str
Преобразует одну страницу в простой текст. Принимает параметры преобразования для единообразия API, хотя большинство из них применяются преимущественно к Markdown/HTML-выводу.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
page_index |
int / usize |
– | Индекс страницы (начиная с нуля) |
preserve_layout |
bool |
false |
Сохранять визуальный макет |
detect_headings |
bool |
true |
Обнаруживать заголовки |
include_images |
bool |
true |
Включать изображения |
image_output_dir |
str / None |
None |
Директория для сохранения изображений |
Python
doc = PdfDocument("paper.pdf")
text = doc.to_plain_text(0)
Node.js
const doc = new PdfDocument("paper.pdf");
const text = doc.toPlainText(0);
Go
doc, _ := pdfoxide.Open("paper.pdf")
defer doc.Close()
text, _ := doc.ToPlainText(0)
C#
using var doc = PdfDocument.Open("paper.pdf");
string text = doc.ToPlainText(0);
WASM
const doc = new WasmPdfDocument(bytes);
const text = doc.extractText(0);
Rust
use pdf_oxide::converters::ConversionOptions;
let mut doc = PdfDocument::open("paper.pdf")?;
let options = ConversionOptions::default();
let text = doc.to_plain_text(0, &options)?;
C++
auto doc = pdf_oxide::Document::open("paper.pdf");
auto text = doc.to_plain_text(0);
Swift
let doc = try Document.open("paper.pdf")
let text = try doc.toPlainText(0)
Dart
final doc = PdfDocument.open('paper.pdf');
final text = doc.toPlainText(0);
R
doc <- pdf_open("paper.pdf")
text <- pdf_to_plain_text(doc, 0)
Julia
doc = open_document("paper.pdf")
text = to_plain_text(doc, 0)
Zig
var doc = try pdf_oxide.Document.open("paper.pdf");
const text = try doc.toPlainText(a, 0);
Objective-C
POXDocument *doc = [POXDocument openPath:@"paper.pdf" error:&err];
NSString *text = [doc toPlainText:0 error:&err];
Elixir
{:ok, doc} = PdfOxide.open("paper.pdf")
{:ok, text} = PdfOxide.to_plain_text(doc, 0)
extract_hierarchical_content(page_index) -> Option<StructureElement>
Извлекает содержимое страницы в виде иерархического дерева структуры. Для нетегированных PDF возвращает None. Для тегированных PDF возвращает дерево StructureElement, отражающее логическую структуру документа (заголовки, абзацы, таблицы, рисунки).
| Параметр | Тип | Описание |
|---|---|---|
page_index |
int / usize |
Индекс страницы (начиная с нуля) |
Rust
let mut doc = PdfDocument::open("tagged-report.pdf")?;
if let Some(root) = doc.extract_hierarchical_content(0)? {
println!("Structure type: {:?}", root.structure_type);
for child in &root.children {
println!(" Child: {:?}", child.structure_type);
}
}
Продвинутые примеры
Построение таблицы частотности слов по span-ам
from collections import Counter
from pdf_oxide import PdfDocument
doc = PdfDocument("report.pdf")
words = Counter()
for page in range(doc.page_count()):
text = doc.extract_text(page)
for word in text.split():
words[word.lower().strip(".,;:!?\"'()[]")] += 1
for word, count in words.most_common(20):
print(f"{word:20s} {count}")
Обнаружение жирных заголовков по метаданным span-ов
use pdf_oxide::PdfDocument;
use pdf_oxide::layout::FontWeight;
let mut doc = PdfDocument::open("paper.pdf")?;
let spans = doc.extract_spans(0)?;
let headings: Vec<_> = spans.iter()
.filter(|s| s.font_weight == FontWeight::Bold && s.font_size > 14.0)
.collect();
for h in headings {
println!("Heading: '{}' ({}pt)", h.text, h.font_size);
}
Экспорт посимвольных данных в CSV
import csv
from pdf_oxide import PdfDocument
doc = PdfDocument("report.pdf")
chars = doc.extract_chars(0)
with open("characters.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["char", "x", "y", "width", "height", "font", "size"])
for ch in chars:
writer.writerow([
ch.char, ch.bbox[0], ch.bbox[1],
ch.bbox[2], ch.bbox[3],
ch.font_name, ch.font_size,
])
Извлечение векторных путей
extract_paths() возвращает данные векторных путей (линии, кривые, прямоугольники) со страницы. Полезно для обнаружения границ таблиц, разделителей и графических элементов.
doc = PdfDocument("report.pdf")
paths = doc.extract_paths(0)
for path in paths:
for op in path["operations"]:
print(f"{op['type']}: {op.get('x', '')}, {op.get('y', '')}")
# types: move_to, line_to, curve_to, rectangle, close_path
Связанные страницы
- Конвертация в Markdown – Преобразование текста в структурированный Markdown
- Конвертация в HTML – Преобразование текста в HTML с форматированием
- Поиск по тексту – Поиск в извлечённом тексте по регулярным выражениям
- Метаданные и XMP – Чтение метаданных уровня документа