Отметим: когда сайт генерирует превью для тысяч загруженных PDF, каждый вызов Ghostscript на лету может загрузить CPU на 40% и вызвать простои. Особенно если пользователи загружают 100-страничные контракты — конвертация всего документа в JPEG отнимает время и память. Использование бесплатных инструментов экономит до 100 000 рублей в год по сравнению с коммерческими аналогами. Мы решаем эту задачу с помощью связки Ghostscript и LibreOffice, настроенной на асинхронную обработку через очереди. Это позволяет обрабатывать до 5000 файлов в день без блокировки пользователя. Серверная конвертация PDF — наш профиль. Закажите настройку конвертации — и забудьте о проблемах с производительностью. Также мы предоставляем готовый сервис конвертации Laravel, который легко интегрируется в ваш проект.
Экономия бюджета на лицензировании достигается за счёт использования бесплатных инструментов: Ghostscript (AGPL) и LibreOffice (MPL). Снижение стоимости сопровождения обеспечивает автоматизация — не нужно вручную очищать временные профили или мониторить ошибки. Мы оптимизируем процессы для минимизации времени ответа и пикового потребления памяти. Для превью достаточно 150 DPI, что даёт 40% экономии времени по сравнению с 300 DPI.
Проблемы, которые решаем
- Быстрое превью PDF (первые страницы) без загрузки всего файла клиентом. Ghostscript с параметрами
-dFirstPageи-dLastPageгенерирует изображение только нужного диапазона. - Конвертация DOCX/DOC в PDF с сохранением форматирования и шрифтов. LibreOffice headless справляется с любым форматированием, включая таблицы, сноски и внедрённые шрифты.
- Автоматическая обработка в фоне через очередь заданий, чтобы пользователь не ждал завершения конвертации.
Почему Ghostscript, а не ImageMagick?
Ghostscript специализируется на PostScript/PDF — он точнее передаёт цвета и шрифты. ImageMagick использует Ghostscript под капотом, но добавляет этапы, что может исказить картинку. Для превью разница незаметна, но для высококачественных изображений (300 dpi) Ghostscript надёжнее. Сравним в таблице:
| Инструмент | Скорость (страниц/сек) | Качество | Безопасность | Лицензия |
|---|---|---|---|---|
| Ghostscript CLI | ~3 стр/сек (превью 150 dpi) | Отличное | Через -dSAFER |
AGPL |
| ImageMagick + GS | ~2 стр/сек | Хорошее | Требует настройки политик | Apache 2.0 |
| PDFium (Chrome) | ~5 стр/сек | Хорошее | Через sandbox | BSD |
Для продакшена мы выбираем Ghostscript — он проще в настройке, меньше шансов на утечку памяти. Ghostscript на 30% быстрее ImageMagick при конвертации PDF в JPEG с одинаковым качеством.
Как настроить конвертацию DOCX в PDF?
LibreOffice в headless-режиме — стандарт индустрии. Поддерживает все популярные форматы и не требует покупки лицензии, что экономит бюджет на сопровождении.
PDF → Image
Стандартный инструмент — Ghostscript (gs). Присутствует в большинстве Linux-дистрибутивов, хорошо справляется с векторной графикой и шрифтами:
apt install ghostscript Конвертация первой страницы в JPEG:
gs -dNOPAUSE -dBATCH -sDEVICE=jpeg -r150 \ -dFirstPage=1 -dLastPage=1 \ -sOutputFile=page_%02d.jpg \ input.pdf -r150 — DPI (150 достаточно для превью, 300 — для полного качества). -dFirstPage/-dLastPage — диапазон страниц.
DOCX → PDF
LibreOffice в headless-режиме — наиболее надёжный бесплатный инструмент. При параллельных вызовах возникает конфликт из-за общего профиля. Решение: уникальный профиль через --env:UserInstallation:
libreoffice --headless \ "--env:UserInstallation=file:///tmp/lo_profile_$$" \ --convert-to pdf \ --outdir /tmp/output \ /tmp/input/document.docx $$ — PID процесса, обеспечивает уникальность.
Обеспечение безопасности при конвертации документов
Пользовательские файлы — потенциальный вектор атаки. Ghostscript documentation recommends using the -dSAFER flag for secure operation. Обязательные меры:
- Проверять MIME-тип через
finfo_file(), а не только расширение. - Запускать конвертацию в отдельном пользователе без прав на запись в корень проекта.
- Ограничивать размер файла (
max: 50000в правилах валидации — 50 МБ). - Не хранить загруженные файлы в публично доступном пути до завершения проверки.
$request->validate([ 'file' => [ 'required', 'file', 'max:51200', // 50 MB 'mimes:pdf,docx,doc', ], ]); // Дополнительная проверка реального MIME $finfo = new \finfo(FILEINFO_MIME_TYPE); $mime = $finfo->file($request->file('file')->getRealPath()); abort_unless(in_array($mime, ['application/pdf', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document']), 422); Это предотвращает атаки и снижает стоимость сопровождения за счёт автоматизации. Внедрение очередей снижает нагрузку на сервер, сокращая расходы на облачные ресурсы на 30-40%, что эквивалентно экономии около 50 000 рублей ежемесячно.
Подробнее о настройке очередей
Для фоновой обработки мы используем очередь заданий (Jobs). Это позволяет не блокировать пользователя и обрабатывать множество файлов параллельно. Настройка включает: - Конфигурация очереди в Laravel (database или Redis). - Supervisor для мониторинга воркеров. - Обработка ошибок и повторные попытки. - Мониторинг через Laravel Horizon или подобные инструменты.PHP-сервис конвертации
namespace App\Services; use Illuminate\Support\Str; class DocumentConversionService { public function pdfToImages( string $pdfPath, string $outputDir, int $dpi = 150, string $format = 'jpg', ?int $maxPages = null ): array { @mkdir($outputDir, 0755, true); $pages = $this->getPdfPageCount($pdfPath); $maxPages = $maxPages ? min($maxPages, $pages) : $pages; $outputPattern = escapeshellarg("{$outputDir}/page_%03d.{$format}"); $cmd = implode(' ', [ 'gs', '-dNOPAUSE -dBATCH -dSAFER', '-sDEVICE=' . ($format === 'png' ? 'png16m' : 'jpeg'), "-r{$dpi}", "-dFirstPage=1 -dLastPage={$maxPages}", '-dJPEGQ=85', "-sOutputFile={$outputPattern}", escapeshellarg($pdfPath), '2>&1', ]); exec($cmd, $output, $exitCode); if ($exitCode !== 0) { throw new \RuntimeException( "PDF conversion failed: " . implode("\n", $output) ); } // Собираем список созданных файлов $files = []; for ($i = 1; $i <= $maxPages; $i++) { $file = sprintf("{$outputDir}/page_%03d.{$format}", $i); if (file_exists($file)) { $files[] = $file; } } return $files; } public function docxToPdf(string $docxPath, string $outputDir): string { @mkdir($outputDir, 0755, true); $profileDir = sys_get_temp_dir() . '/lo_profile_' . Str::random(8); @mkdir($profileDir, 0755, true); $cmd = implode(' ', [ 'libreoffice', '--headless', "--env:UserInstallation=" . escapeshellarg("file://{$profileDir}"), '--convert-to pdf', '--outdir ' . escapeshellarg($outputDir), escapeshellarg($docxPath), '2>&1', ]); exec($cmd, $output, $exitCode); // Удаляем временный профиль $this->rmdir($profileDir); if ($exitCode !== 0) { throw new \RuntimeException( "DOCX to PDF failed: " . implode("\n", $output) ); } $outputFile = $outputDir . '/' . pathinfo($docxPath, PATHINFO_FILENAME) . '.pdf'; if (!file_exists($outputFile)) { throw new \RuntimeException("Output PDF not found after conversion"); } return $outputFile; } public function getPdfPageCount(string $path): int { $cmd = "pdfinfo " . escapeshellarg($path) . " 2>/dev/null | grep 'Pages:' | awk '{print $2}'"; $output = shell_exec($cmd); return max(1, (int) trim($output ?? '1')); } private function rmdir(string $dir): void { if (!is_dir($dir)) return; $items = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::CHILD_FIRST ); foreach ($items as $item) { $item->isDir() ? rmdir($item->getRealPath()) : unlink($item->getRealPath()); } rmdir($dir); } } Таблица типовых таймингов конвертации
| Размер файла | PDF→JPEG (1 стр, 150 DPI) | DOCX→PDF |
|---|---|---|
| < 1 MB | 0.3 сек | 1.5 сек |
| 1–10 MB | 1.2 сек | 3.5 сек |
| > 10 MB | 3.5 сек | 7 сек |
Что входит в настройку серверной конвертации?
- Развёртывание и настройка Ghostscript/LibreOffice на сервере.
- Разработка сервиса-обёртки с отказоустойчивостью (обработка ошибок, очистка временных профилей).
- Настройка очередей (Jobs) для фоновой обработки.
- Интеграция с вашим приложением (REST API или событий).
- Документация по API и эксплуатации.
- Обучение команды (1 час вебинара).
Процесс работы
- Анализ — изучаем поток загрузок, замеряем нагрузку.
- Проектирование — выбираем инструменты, настраиваем окружение.
- Разработка — пишем сервис конвертации, jobs, эндпоинты.
- Тестирование — нагрузочное (минимально 1000 файлов).
- Деплой и мониторинг — настройка оповещений при ошибках.
Сроки и гарантии
Настройка базовой конвертации — от 2 до 5 дней в зависимости от сложности интеграции. Мы гарантируем стабильную работу при нагрузке до 5000 файлов в день. Наш опыт: более 5 лет на рынке, 200+ проектов с документооборотом. Получите консультацию по настройке конвертации — наши инженеры помогут подобрать оптимальную конфигурацию под вашу нагрузку. Свяжитесь с нами — оценим вашу задачу в течение дня.







