
Отправьте насыщенный цветами отчёт на офисный монохромный лазерный принтер — и вы заплатите за это дважды: сначала тонером, который принтер тратит впустую, пытаясь имитировать серый из CMYK-точек, а затем качеством результата — растровые заливки и заливки диаграмм превращаются в мутную рябь вместо чистых тонов. Отправьте тот же файл в архив документов — и цвет окажется хуже, чем бесполезен. Плашечные цвета стареют, цветопередача смещается от машины к машине, и каждая повторная печать получается чуть отличающейся от предыдущей. Оттенки серого — это формат, который нужен обеим этим задачам, и до него всего один вызов, когда PDF обрабатывается в коде.
В этой статье PDF превращается в документ в оттенках серого прямо в браузере с помощью Spire.PDF для JavaScript. Библиотека скомпилирована в WebAssembly и управляет документом через виртуальную файловую систему (VFS), поэтому файл читается и перезаписывается на машине пользователя, и ничего не передаётся в сервис конвертации.
По настройке проекта следуйте руководству Интеграция Spire.PDF для JavaScript в проект React. Пример ниже предполагает, что пакет установлен, а модуль WebAssembly завершил инициализацию.
Зачем переводить PDF в оттенки серого (и когда это неверный шаг)
Три ситуации возникают снова и снова:
- Печать на монохромном оборудовании. У монохромного лазерного принтера один тонер. Когда вы отдаёте ему цветной PDF, он вынужден аппроксимировать каждый цвет растровым узором — именно поэтому цветной текст и тонкие линии диаграмм выходят размытыми. Источник в оттенках серого убирает догадки — принтер получает тон, а не цвет для интерпретации.
- Документы и архивирование. Стандарты долгосрочного хранения строятся вокруг фиксированного, независимого от устройства внешнего вида. Документ в оттенках серого воспроизводится одинаково на любом принтере и любом сканере, поэтому архивная копия не может «уплыть».
- Конвейеры сканирования и индексирования. Как только документ отсканирован и распознан (OCR), цвет не несёт информации, которую мог бы использовать индекс — это только вес.
Есть случаи, когда лучше ничего не трогать. Если цвет выполняет смысловую работу — диаграмма, где каждый ряд имеет свой оттенок, фирменный материал, портфолио фотографий — перевод в оттенки серого уничтожает именно то, что нужно читателю. Это также неверный инструмент, когда настоящая проблема — размер: если цель — меньший файл, а не более дешёвая печать, то перевод в оттенки серого воздействует только на изображения и игнорирует шрифты и потоки содержимого — для этого нужен компрессор.
Что на самом деле меняет оттенки серого
Легко предположить, что «оттенки серого» означают, что страница перерисовывается как картинка. Это не так. Преобразование работает на уровне объектов:
| Часть страницы | Что происходит |
|---|---|
| Цветные изображения | Перекодируются в одноканальные оттенки серого: одно значение яркости на пиксель вместо трёх цветовых каналов |
| Текст | Остаётся нетронутым как текст — по-прежнему выделяемый, доступный для поиска и копирования |
| Макет и число страниц | Не изменяются; ничего не обрезается, не перемещается и не удаляется |
| Метаданные документа | Сохраняются |
Поскольку изображения перекодируются, а не растрируются в скриншот, на выходе получается обычный PDF с меньшим цветовым пространством — а не картинка с PDF. Эта разница важна в тот момент, когда кто-то пытается выполнить поиск по результату или выделить строку текста.
Преобразование документа в оттенки серого
Работу выполняют два члена: передайте входной файл в конструктор PdfGrayConverter, затем вызовите ToGrayPdf с выходным файлом. Остальная часть компонента — это обычная загрузка в VFS и скачивание Blob.
function App() {
const convertToGrayscale = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check whether the module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the PDF file to be converted into the VFS
const inputFileName = 'Business_Data_Overview.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// Define the output file name
const outputFileName = 'GrayscaleDocument.pdf';
// Construct the grayscale converter from the input file and write out the grayscale document
const converter = new pdfModule.PdfGrayConverter({ filePath: inputFileName });
converter.ToGrayPdf({ filePath: outputFileName });
converter.Dispose();
// 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>Convert PDF to Grayscale</h1>
<button onClick={convertToGrayscale}>
Start Converting
</button>
</div>
);
}
export default App;
Стоит обратить внимание на три детали. ToGrayPdf записывает новый файл — входной файл в VFS остаётся таким, каким был, поэтому опция «сохранить цветную версию» ничего не стоит. Dispose освобождает конвертер после записи файла. И именно цветные изображения на странице фактически перезаписываются этим вызовом; текст никогда не становится изображением.
Образец документа после перевода в оттенки серого, где цветные диаграммы стали серыми

Оттенки серого, обесцвечивание и черно-белый
Три разных результата в повседневной речи называют «оттенками серого», но это не один и тот же файл:
| Результат | Как он хранится | Размер данных изображения | Где он уместен |
|---|---|---|---|
| Настоящие оттенки серого | Один канал, DeviceGray
|
Наименьший — одно значение на пиксель | Печать, архивирование, обычные документы |
| Обесцвеченный цвет | Три равных канала, DeviceRGB с R=G=B |
Примерно втрое больше данных, чем в оттенках серого | Быстрый визуальный фильтр, когда файл уже существует |
| Пороговый черно-белый | Один бит на пиксель, без полутонов | Крошечный | Отсканированные текстовые страницы, где зерно — шум, а не деталь |
На экране первые два неразличимы; разница полностью в том, сколько байт стоит каждый пиксель и как принтер должен его интерпретировать. Пороговое преобразование — совершенно другая операция: оно отбрасывает полутона, поэтому фотографии превращаются в пятна, и выживают только линейная графика и чистый текст.
Конвертер записывает первый вид: одноканальное изображение в оттенках серого — именно поэтому оно также самое дешёвое из трёх по объёму хранения.
Побочный эффект: размер файла
Оттенки серого — это не функция сжатия, но они уменьшают файлы, и стоит понимать почему. В образце документа цветные изображения были трёхканальными PNG общим объёмом около 66 КБ; после преобразования те же изображения стали примерно 31 КБ. Весь файл уменьшился с 82 КБ до 44 КБ — примерно на 46%, и это достигнуто исключительно за счёт отказа от цветовых каналов. Число страниц и текст не изменились вовсе.
Это достаётся бесплатно вместе с экономией тонера. Но читайте цифру правильно: выигрыш масштабируется в зависимости от того, какую часть файла составляют растровые изображения. В документе, который в основном состоит из текста и векторной графики, почти нечего перекодировать, поэтому перевод в оттенки серого едва изменит размер — а если цель именно размер, изображения являются лишь одним из трёх мест, где скрывается вес. Уменьшение размера PDF-файла в JavaScript (React) рассказывает о двух других.
Интеграция в интерфейс React
В реальном компоненте описанный выше шаблон требует двух доработок.
Не оставляйте alert. Модуль WebAssembly загружается асинхронно, поэтому первый клик может произойти раньше, чем конвертер станет доступен. Отключайте кнопку, пока модуль не сообщит о готовности, вместо того чтобы прерывать пользователя диалогом:
// The module may not have finished loading on the first render
const [ready, setReady] = useState(false);
// ...
<button disabled={!ready} onClick={convertToGrayscale}>Convert to Grayscale</button>
Объединяйте вызовы в пакет. Поскольку конвертер принимает по одному файлу и записывает по одному файлу, папка документов — это просто цикл: тот же конструктор, тот же метод, другое имя выходного файла для каждого входного:
// The converter is a one-file operation, so a batch is a loop
for (const name of inputNames) {
await window.spire.FetchFileToVFS(name, "", `${process.env.PUBLIC_URL}/data/`);
const out = name.replace(/\.pdf$/i, '-gray.pdf');
const converter = new pdfModule.PdfGrayConverter({ filePath: name });
converter.ToGrayPdf({ filePath: out });
converter.Dispose();
// read out from the VFS and download (or report per-file sizes)
}
Поскольку и оригинал, и копия в оттенках серого находятся в VFS, вы можете показывать рядом с каждой строкой реальную цифру «до и после» вместо простой ссылки:
// Both files are in the VFS, so the saving can be measured
const before = window.dotnetRuntime.Module.FS.readFile(name).length;
const after = window.dotnetRuntime.Module.FS.readFile(out).length;
Показ сэкономленного процента превращает кнопку в результат. Если два числа почти равны, значит, в изображениях документа нечего было отдавать — это информация, а не ошибка.
Частые проблемы
В выходном файле появляется дополнительная строка предупреждения.
Незалицензированная сборка вставляет в документ строку Evaluation Warning : The document was created with Spire.PDF for JavaScript., и она добавляется при каждом вызове — преобразуйте один и тот же файл дважды за сеанс, и строка появится дважды. Временная лицензия убирает её; свяжитесь с отделом продаж, чтобы получить 30-дневный ключ, который также снимает функциональные ограничения.
Преобразованный документ выглядит точно так же. Проверьте, из чего состоит документ. Если это текст и векторная графика без растровых изображений, переводу в оттенки серого почти нечего менять, и разница будет незаметна. Это ожидаемо, а не ошибка.
При первом клике ничего не происходит. Модуль всё ещё загружался. Защитите обработчик проверкой ссылки на модуль или держите кнопку отключённой, пока модуль не готов, как показано выше.
Файл почти не уменьшился. Перевод в оттенки серого затрагивает только изображения. Если вес заключается в шрифтах или потоках содержимого, это преобразование — не тот рычаг; см. статью о сжатии по ссылке выше.
Часто задаваемые вопросы
Делает ли преобразование в оттенки серого текст невыделяемым? Нет. Текст не растрируется. Перекодируются только изображения, поэтому результат по-прежнему доступен для поиска, выделения и копирования — просто в нём нет цвета.
Можно ли преобразовать только некоторые страницы? Конвертер работает с документом целиком. Если часть файла должна остаться цветной, сначала разделите документ, преобразуйте ту часть, которая должна стать серой, а затем объедините части обратно.
Всегда ли перевод в оттенки серого уменьшает размер файла? Не всегда, но обычно немного — экономия идёт от изображений, поэтому чем больше растровых данных, тем больше выигрыш. Документы, которые уже состоят из текста и векторной графики, могут почти не измениться.
Нужно ли куда-то загружать файл? Нет. Всё происходит в браузере. PDF попадает в виртуальную файловую систему, перезаписывается там и считывается обратно для скачивания, поэтому конфиденциальный документ никогда не покидает устройство.
Могу ли я предложить пользователю обе версии?
Да. ToGrayPdf записывает в новое имя файла и оставляет входной файл нетронутым, поэтому цветной оригинал и копия в оттенках серого доступны в одном сеансе.
См. также
- Линеаризация PDF для быстрого веб-просмотра в JavaScript (React)
- Уменьшение размера PDF-файла: изображения, шрифты и потоки содержимого в JavaScript (React)
- Как преобразовать страницы PDF в изображения в JavaScript (React)
- Интеграция Spire.PDF для JavaScript в проект React
- Страница продукта Spire.PDF для JavaScript