
PDF редко бывает просто «слишком большим». Он слишком большой для одной конкретной двери — ограничения на вложение в почте, формы загрузки, квоты хранилища — и то, что вытолкнуло его за этот предел, обычно является одной из трёх вещей. Сжимать, не зная, какой именно, — значит гадать, а гадание стоит либо качества, либо ещё одной неудачной загрузки.
Spire.PDF for JavaScript даёт вам компрессор с опцией для каждого из этих трёх мест. Их можно применять по отдельности или вместе, и компромиссы достаточно различны, чтобы стоило понять каждый, прежде чем решать. Всё выполняется в браузере на WebAssembly, а файлы перемещаются через виртуальную файловую систему (VFS), поэтому документ не нужно загружать в сторонний сервис, чтобы уменьшить его размер.
По настройке проекта см. Интеграция Spire.PDF for JavaScript в проект React. Примеры ниже предполагают, что пакет установлен и модуль WebAssembly инициализирован.
Что на самом деле делает PDF большим
Размер файла PDF складывается из трёх разных мест, и ведут они себя совершенно по-разному:
| Где сосредоточен вес | Как это выглядит | Признак, что причина в этом |
|---|---|---|
| Изображения | Растровые изображения, встроенные в собственном разрешении — сканы, фотографии, экспортированные скриншоты | Мало страниц, десятки мегабайт |
| Встроенные шрифты | Шрифтовые программы, хранящиеся внутри файла, чтобы текст одинаково отображался везде | В основном текст, но всё ещё несколько мегабайт |
| Потоки содержимого | Инструкции рисования, стоящие за текстом и векторной графикой | Файл редактировался или пересохранялся несколькими разными инструментами |
Два документа одинаковой длины могут различаться на порядок из-за этого: пятистраничный сканированный договор может весить 20 МБ, тогда как пятидесятистраничный текстовый отчёт укладывается в 1 МБ. Вот почему у вопроса «насколько я могу это сжать?» нет единственного ответа — файл с обилием сканов может многое вернуть, а документ, который уже в основном состоит из текста и векторной графики, близок к своему минимуму.
Поэтому сначала нужна диагностика. Сжатие документа с большим объёмом текста настройками изображений почти ничего не даёт, а сжатие изображений в документе, вес которого на самом деле в шрифтах, тратит качество без выигрыша.
Три рычага сжатия
PdfCompressor предоставляет свою стратегию через Options, и каждая группа настроек соответствует одному из трёх источников выше:
| Параметр | На что нацелен | Чем вы жертвуете |
|---|---|---|
ImageCompressionOptions |
Растровые изображения на странице | Точность изображений — это единственный рычаг с потерями из трёх |
TextCompressionOptions |
Данные встроенных шрифтов | Ничем, если только вы не удаляете встроенные шрифты — тогда переносимостью |
CompressContents |
Потоки содержимого страницы | Практически ничем — содержимое перекодируется, а не отбрасывается |
Следующие три раздела рассматривают их по одному, чтобы эффект каждого был виден отдельно. Раздел после них объединяет их, что обычно и нужно в продакшене.
Сжатие изображений
Растровые изображения с высоким разрешением — самая распространённая единственная причина PDF завышенного размера, и именно там наибольший выигрыш. Options.ImageCompressionOptions управляет масштабированием и перекодированием через три свойства:
| Свойство | Что делает | Когда стоит устанавливать |
|---|---|---|
ResizeImages |
Пропорционально уменьшает изображения, затем перекодирует их | Фотографии или сканы, снятые с разрешением намного выше того, при котором они отображаются |
CompressImage |
Применяет к изображениям перекодирование с потерями | Когда качество изображений вообще можно немного снизить |
ImageQuality |
Выбирает уровень качества для этого перекодирования | Последняя настройка — High сохраняет больше деталей, Low даёт меньший файл |
// Compress images in the document: resize, re-compress, and lower the quality
compressor.Options.ImageCompressionOptions.ResizeImages = true;
compressor.Options.ImageCompressionOptions.CompressImage = true;
compressor.Options.ImageCompressionOptions.ImageQuality = pdfModule.ImageQuality.Low;
ImageQuality сам по себе ничего не делает — он лишь описывает, как кодируются изображения, проходящие через первые два свойства, поэтому установка только его возвращает вам тот же файл. И поскольку это единственный рычаг с потерями, сначала протестируйте на уровне High, если PDF будет печататься, а не читаться на экране.
Шрифты: сжимать или удалять встроенные
Чтобы текст одинаково отображался на машинах, где нет исходных шрифтов, PDF содержит шрифтовые программы, используемые в его тексте, внутри файла. Они могут быть подмножествами, но отсутствующими не являются — а несколько семейств с несколькими начертаниями в сумме дают немало. Options.TextCompressionOptions предлагает два совершенно разных способа справиться с этим:
| Свойство | Что делает | Подвох |
|---|---|---|
CompressFonts |
Сжимает данные встроенных шрифтов и оставляет шрифты на месте | Нет для отображения — глифы остаются в файле |
UnembedFonts |
Удаляет шрифтовые программы и позволяет программе просмотра подставлять системные шрифты | Подмена глифов или смещение интервалов там, где этих шрифтов нет |
// Compress font data; UnembedFonts goes further and removes the embedded fonts
compressor.Options.TextCompressionOptions.CompressFonts = true;
compressor.Options.TextCompressionOptions.UnembedFonts = true;
Комбинация выше — агрессивная, и она безопасна ровно при одном условии: вы знаете, что будет отображать документ. Ссылка для скачивания или письмо неизвестному получателю — это не такое условие; там оставьте шрифты встроенными и дайте CompressFonts сделать работу. Удаляйте встроенные шрифты только там, где набор шрифтов фиксирован, например во внутренней программе просмотра с известной конфигурацией.
Повторное сжатие потоков содержимого
Текст и команды векторной отрисовки на странице находятся в потоках содержимого. Они сжимаются при записи PDF, но документ, который многократно редактировался или передавался между разными инструментами, может накапливать в них избыточность. Options.CompressContents перекодирует эти потоки:
// Re-compress the document content streams
compressor.Options.CompressContents = true;
Сам по себе это наименее впечатляющий из трёх — не ожидайте, что он спасёт документ с обилием фотографий. Он оправдывает себя в насыщенных текстом документах со сложной вёрсткой, и это самый безопасный рычаг, который можно оставить включённым, поскольку перекодирование потока не меняет то, что он рисует.
Все три за один проход
Эти три измерения — не три отдельных запуска. Вы направляете один PdfCompressor на файл, задаёте столько опций, сколько нужно, и записываете результат один раз с помощью CompressToFile.
Пример ниже включает изменение размера и повторное сжатие изображений на уровне High, сжатие шрифтов с удалением встроенных и повторное сжатие потоков содержимого — для документа, содержащего как изображения с высоким разрешением, так и основной текст:
function App() {
const compressPdfDocument = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check that the module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the PDF to be compressed into the VFS
const inputFileName = 'ImageDocument.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// Create a PdfCompressor and point it at the PDF to compress
let compressor = new pdfModule.PdfCompressor({ filePath: inputFileName });
// 1. Image compression: resize and re-compress images, with a higher quality tier
compressor.Options.ImageCompressionOptions.ResizeImages = true;
compressor.Options.ImageCompressionOptions.CompressImage = true;
compressor.Options.ImageCompressionOptions.ImageQuality = pdfModule.ImageQuality.High;
// 2. Font compression: compress font data and remove embedded fonts
compressor.Options.TextCompressionOptions.CompressFonts = true;
compressor.Options.TextCompressionOptions.UnembedFonts = true;
// 3. Content compression: re-compress the document content streams
compressor.Options.CompressContents = true;
// Define the output file name and compress to it
const outputFileName = 'CompressedDocument.pdf';
compressor.CompressToFile(outputFileName);
// Read the generated file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Compress PDF Document</h1>
<button onClick={compressPdfDocument}>
Generate
</button>
</div>
);
}
export default App;
PDF-документ, сжатый сочетанием всех трёх подходов

Два замечания о форме этого кода. Оригинал остаётся в VFS нетронутым — CompressToFile записывает новый документ, поэтому доступен выбор до и после. И поскольку компрессор работает с ресурсами документа, а не с отрендеренными страницами, текст остаётся настоящим текстом: всё ещё выделяемым, всё ещё доступным для поиска. Перекодируются только изображения.
Проверка изменений
Оба файла находятся в VFS, поэтому вы можете сравнить их, прежде чем отдавать результат пользователю, вместо того чтобы гадать, дали ли настройки какой-либо эффект:
// Both the original and the compressed copy are in the VFS
const originalBytes = window.dotnetRuntime.Module.FS.readFile(inputFileName).length;
const compressedBytes = window.dotnetRuntime.Module.FS.readFile(outputFileName).length;
Сообщайте разницу в процентах рядом с загрузкой, а не предлагайте голую кнопку — это сразу говорит пользователю, достаточно ли файл мал для того места, куда он направляется. Если два числа почти одинаковы, вес был не там, где вы сжимали.
Подбор настроек под документ
| Документ | Включить | На что обратить внимание |
|---|---|---|
| Сканированные страницы, фотографии, скриншоты |
ResizeImages, CompressImage, ImageQuality, настроенные под экран или печать |
Мелкие детали внутри скана размываются первыми — проверьте на High перед публикацией |
| В основном текст и векторная графика |
CompressFonts, CompressContents
|
Выигрыш по своей природе скромный; не гонитесь за ним с помощью настроек изображений |
| Смешанное содержимое | Все три, при ImageQuality.High
|
Самый безопасный универсальный профиль, и обычно лучшее место для начала |
| Уже оптимизирован для распространения | Только CompressContents
|
Мало что можно выиграть; агрессивное перекодирование изображений может стоить качества почти ни за что |
Частые проблемы
Файл почти не уменьшился, а в PDF почти нет изображений.
Размер идёт из шрифтов или потоков содержимого. Включите TextCompressionOptions — с UnembedFonts только если среда просмотра известна — и добавьте CompressContents. Насыщенные текстом документы реагируют на эти две настройки и ни на что другое.
Текст отображается иначе после сжатия.
Это UnembedFonts делает ровно то, что заявлено. Верните его в false и оставьте CompressFonts = true; данные шрифтов всё равно сжимаются, но глифы остаются в файле.
Изображения выглядят размытыми или блочными в выходном файле.
Либо уровень ImageQuality слишком низкий, либо ResizeImages уменьшил изображение, которому для печати нужно было его разрешение. Для всего, что будет печататься, начинайте с High.
Сжатый файл такого же размера, как оригинал. Некоторые документы уже оптимизированы и не имеют ничего значимого, что можно отдать. Проверьте с помощью сравнения байтов выше, вместо того чтобы предполагать, что настройки не сработали.
Ничего не происходит при первом клике.
Модуль WebAssembly загружается асинхронно. Для этого и нужна проверка if (!pdfModule) return; — в реальном приложении отключайте кнопку, пока модуль не сообщит о готовности, вместо показа предупреждения.
Часто задаваемые вопросы
За какой рычаг взяться первым?
За изображения, если предполагать, что виноваты они — но подтвердите это. Если документ насыщен текстом и непропорционален своему количеству страниц, начните со шрифтов и потоков содержимого и не трогайте настройки изображений.
Делает ли сжатие PDF его текст нечитаемым или невыделяемым?
Нет, и именно здесь компрессор на основе API отличается от онлайн-инструментов, которые растрируют каждую страницу в JPEG. Текст остаётся текстом, векторная графика остаётся векторной, и затрагиваются только растровые изображения — поэтому сжатая копия всё ещё выделяемая, доступная для поиска и пригодная для печати.
Можно ли сжать только часть документа?
Компрессор работает с документом как с целым. Если вам нужно уменьшить часть файла, а часть оставить нетронутой, сначала разделите документ, сожмите нужный фрагмент и снова объедините.
Можно ли сохранить оригинал и предложить сжатую копию на выбор?
Да. CompressToFile записывает в новое имя файла и оставляет входной файл в VFS, поэтому обе версии доступны в одной сессии — это полезно, когда пользователь решает, сколько качества обменять.
Нужен ли для этого сервер, или это может работать полностью в браузере?
Полностью в браузере. PDF-движок скомпилирован в WebAssembly, а файлы перемещаются через VFS, поэтому документ никогда не покидает устройство. Это особенно важно именно для тех документов, которые люди обычно хотят уменьшить — договоров, выписок, записей.