Skip to content

Сжатие PDF

DocumentEditor::save_with_options() умеет за один проход пересжимать потоки, собирать мусор из бесхозных объектов и линеаризовать файл под быструю web-отдачу. Проще всего включить всё это разом с помощью CLI pdf-oxide compress, которая прячет их за одной командой.

Покрытие биндингами. Полный SaveOptions с compress / garbage_collect / linearize доступен в Rust (editor.save_with_options(path, opts)) и Python (через doc.save(..., compress=True, ...) там, где он прокинут). Из Node, WASM, Go и C# запускайте CLI (pdf-oxide compress input.pdf -o out.pdf) как подпроцесс или на этапе сборки — CLI остаётся стабильным интерфейсом, общим для этих биндингов, пока SaveOptions не будет проведён через каждый FFI.

CLI (все платформы)

# Базовый вариант: создаёт input_compressed.pdf
pdf-oxide compress input.pdf

# Явное имя выходного файла
pdf-oxide compress input.pdf -o smaller.pdf

# Вывести сравнение размеров
pdf-oxide compress report.pdf
# → Compressed report.pdf -> report_compressed.pdf (3412901 -> 1847200 bytes)

CLI по умолчанию включает compress: true, garbage_collect: true, linearize: true — именно эта комбинация даёт наименьший файл, оставаясь валидной по ISO 32000.

Rust API

use pdf_oxide::editor::{DocumentEditor, EditableDocument, SaveOptions};

let mut editor = DocumentEditor::open("input.pdf")?;

editor.save_with_options("output.pdf", SaveOptions {
    compress: true,         // применить FlateDecode ко всем несжатым потокам
    garbage_collect: true,  // удалить бесхозные объекты
    linearize: true,        // линеаризовать под быструю web-отдачу
    ..Default::default()
})?;

Поля SaveOptions

Поле По умолчанию Эффект
compress true в CLI / false по умолчанию Применяет FlateDecode к потокам, сохранённым без сжатия
garbage_collect true в CLI Удаляет косвенные объекты, на которые больше не ссылается трейлер
linearize true в CLI Записывает линеаризованный («Fast Web View») макет, чтобы просмотрщики показывали страницу 1 ещё до полной загрузки файла
encryption None Подключает EncryptionConfig для сохранения с шифрованием — см. Шифрование и безопасность

Что на самом деле делает каждая опция

  • compress — проходит по каждому content stream, Form XObject, ToUnicode CMap и метаданным; если у потока нет фильтра или установлен нераспознанный фильтр, перепаковывает его во FlateDecode. Уже сжатые потоки (изображения JBIG2, таблицы CCITT, существующий Flate) не трогает.
  • garbage_collect — запускает обход достижимости от /Root и /Info, помечает все живые косвенные объекты и записывает в выходной xref только их. Полезно после интенсивного редактирования, когда remove_page, flatten_forms или erase_region оставляют бесхозные объекты.
  • linearize — переупорядочивает объекты так, чтобы content stream первой страницы и её ресурсные зависимости оказались в начале файла, с добавлением словаря линеаризации и hint stream. PDF-ридеры скачивают файл по порядку и отрисовывают первую страницу до его полной загрузки — это главный видимый пользователю плюс для PDF, отдаваемых через CDN.

Когда сжимать

  • После массовых правок — если вы запускали flatten_forms, flatten_all_annotations, apply_all_redactions или удаляли много страниц, GC и пересжатие обычно сокращают размер файла на 30–60 %.
  • Перед рассылкой или распространением — конечный пользователь обращает внимание на размер, а Linearize делает первую страницу мгновенной даже на медленных каналах.
  • Как последний шаг в ETL-конвейерах — после извлечения и повторной генерации сожмите один раз в конце; не распаковывайте и пересжимайте на каждой трансформации.

Когда сжимать НЕ стоит

  • Во время частых инкрементных правок — полная перезапись уничтожает xref stream и object stream, благодаря которым инкрементные дописывания остаются маленькими. В интерактивных циклах редактирования используйте SaveOptions::incremental(), а сжатие оставьте на финальный проход.
  • Для уже агрессивно сжатых PDF — если в потоках уже стоит FlateDecode с хорошим предиктором, вы можете выиграть лишь пару процентов. Запустите pdf-oxide compress один раз и измерьте результат, прежде чем встраивать в конвейер.

Какой размер ожидать

Типичные экономии на реальных PDF (измерено на тестовом наборе из 3830 файлов):

Источник До После Экономия
Отсканированный счёт (несжатые потоки) 2,4 МБ 0,8 МБ ~66 %
LaTeX-статья 1,1 МБ 0,95 МБ ~14 %
Государственная форма (после flatten) 890 КБ 240 КБ ~73 %
Уже оптимизированный маркетинговый PDF 1,8 МБ 1,75 МБ ~3 %

Массово отредактированные файлы и формы после выравнивания дают самый большой выигрыш. Уже оптимизированные файлы выигрывают скромно — в основном за счёт линеаризации.

Сначала расшифруйте и аутентифицируйте

В DocumentEditor пока нет отдельного вызова для аутентификации по паролю, поэтому зашифрованные PDF нужно сначала расшифровать. Используйте PdfDocument.open_with_password() для чтения, сохраните незашифрованную копию и затем откройте её в редакторе:

use pdf_oxide::api::Pdf;
use pdf_oxide::editor::{DocumentEditor, EditableDocument, SaveOptions};

let doc = Pdf::open_with_password("protected.pdf", "pw")?;
doc.save("temp-unencrypted.pdf")?;

let mut editor = DocumentEditor::open("temp-unencrypted.pdf")?;
editor.save_with_options("compressed.pdf", SaveOptions {
    compress: true,
    garbage_collect: true,
    linearize: true,
    ..Default::default()
})?;

Такой же приём в Python через PdfDocument(path, password="pw") + save() + CLI.

Связанные страницы