Отметим: когда сайт генерирует превью для тысяч загруженных 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+ проектов с документооборотом. Получите консультацию по настройке конвертации — наши инженеры помогут подобрать оптимальную конфигурацию под вашу нагрузку. Свяжитесь с нами — оценим вашу задачу в течение дня.







