<!-- Bothost docs | HTML: https://bothost.ru/docs/libreoffice-pdf | Markdown: https://bothost.ru/docs/libreoffice-pdf.md | Index: https://bothost.ru/llms.txt -->

# Генерация PDF из DOCX в Telegram-боте на Bothost: LibreOffice headless

На платформе **Bothost** боты работают в Docker-контейнерах — это удобно для деплоя Telegram-, Discord- и MAX-ботов из Git, но стандартный образ не включает системные пакеты вроде LibreOffice. Если вашему боту нужно конвертировать файлы `.docx` в `.pdf` (договоры, справки, отчёты, счета по шаблону), установите **LibreOffice headless** через кастомный Dockerfile.

LibreOffice headless — это полноценный офисный пакет в фоновом режиме без графического интерфейса. Такой подход подходит для Python-ботов на aiogram, Node.js-ботов и других проектов, развёрнутых на [хостинге ботов Bothost](https://bothost.ru/telegram-bots.html): пользователь отправляет `.docx` в чат, бот возвращает готовый PDF.

---

## Способ 1: Кастомный Dockerfile (рекомендуется)

Добавьте в корень репозитория файл `Dockerfile` и поставьте галочку **«Использовать собственный Dockerfile»** при создании бота.

![Галочка «Использовать собственный Dockerfile» в форме создания бота](images/libreoffice-checkbox.png)

### Dockerfile для Python-бота

```dockerfile
FROM python:3.11-slim

WORKDIR /app

# Устанавливаем LibreOffice headless + шрифты
RUN apt-get update && apt-get install -y --no-install-recommends \
    libreoffice-core \
    libreoffice-writer \
    fonts-dejavu \
    fonts-liberation \
    && rm -rf /var/lib/apt/lists/*

# LibreOffice требует домашнюю директорию
ENV HOME=/root

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["python", "main.py"]
```

> **Важно:** `fonts-dejavu` и `fonts-liberation` — обязательны. Без них кириллица и стандартные шрифты (Arial, Times New Roman) в PDF будут отображаться некорректно.

---

## Конвертация DOCX → PDF в коде

После добавления LibreOffice в образ используйте его через `subprocess`:

```python
import subprocess
import os

def docx_to_pdf(docx_path: str, out_dir: str) -> str:
    """Конвертирует .docx в .pdf через LibreOffice headless."""
    subprocess.run(
        [
            "libreoffice",
            "--headless",
            "--norestore",
            "--convert-to", "pdf",
            "--outdir", out_dir,
            docx_path,
        ],
        check=True,
        timeout=60,
    )
    basename = os.path.splitext(os.path.basename(docx_path))[0]
    return os.path.join(out_dir, basename + ".pdf")
```

### Пример использования в aiogram 3

```python
import os
import tempfile
from aiogram import Bot, Dispatcher, F
from aiogram.types import Message, FSInputFile

bot = Bot(token=os.getenv("BOT_TOKEN"))
dp = Dispatcher()

@dp.message(F.document)
async def handle_document(message: Message):
    doc = message.document
    if not doc.file_name.endswith(".docx"):
        await message.answer("Пришлите файл .docx")
        return

    with tempfile.TemporaryDirectory() as tmpdir:
        # Скачиваем файл
        docx_path = os.path.join(tmpdir, doc.file_name)
        await bot.download(doc, destination=docx_path)

        # Конвертируем
        pdf_path = docx_to_pdf(docx_path, tmpdir)

        # Отправляем обратно
        await message.answer_document(
            FSInputFile(pdf_path),
            caption="Готово! Вот ваш PDF."
        )
```

---

## Способ 2: Node.js-бот

Для Node.js-проектов Dockerfile аналогичный:

```dockerfile
FROM node:20-slim

WORKDIR /app

RUN apt-get update && apt-get install -y --no-install-recommends \
    libreoffice-core \
    libreoffice-writer \
    fonts-dejavu \
    fonts-liberation \
    && rm -rf /var/lib/apt/lists/*

ENV HOME=/root

COPY package*.json ./
RUN npm ci --omit=dev

COPY . .

CMD ["node", "index.js"]
```

Конвертация через `child_process`:

```javascript
const { execFile } = require('child_process');
const path = require('path');

function docxToPdf(docxPath, outDir) {
    return new Promise((resolve, reject) => {
        execFile(
            'libreoffice',
            ['--headless', '--norestore', '--convert-to', 'pdf', '--outdir', outDir, docxPath],
            { timeout: 60000 },
            (err) => {
                if (err) return reject(err);
                const base = path.basename(docxPath, '.docx');
                resolve(path.join(outDir, base + '.pdf'));
            }
        );
    });
}
```

---

## Замечания

| Тема | Подробности |
|------|-------------|
| Размер образа | LibreOffice добавляет ~400–500 МБ. Первая сборка займёт 3–5 минут, повторные — быстрее за счёт кеша |
| Кириллица | Без пакетов `fonts-dejavu` / `fonts-liberation` кириллические символы могут отображаться как квадраты |
| Параллельные запросы | LibreOffice запускается как отдельный процесс при каждой конвертации. Для высокой нагрузки рассмотрите очередь задач |
| Поддерживаемые форматы | Помимо `.docx`, LibreOffice конвертирует `.odt`, `.doc`, `.xlsx`, `.pptx` и другие офисные форматы |

---

## Типичные ошибки

**`LibreOffice не запускается / ошибка профиля`**
Убедитесь, что в Dockerfile есть `ENV HOME=/root`. LibreOffice создаёт временный профиль в домашней директории.

**`Шрифты отображаются некорректно`**
Установите `fonts-dejavu` и `fonts-liberation`. Для специфических шрифтов скопируйте `.ttf`-файлы в `/usr/local/share/fonts/` и выполните `fc-cache -f`.

**`Процесс завис`**
Добавьте `timeout=60` в `subprocess.run()`. LibreOffice иногда зависает на повреждённых файлах.

---

## Когда это нужно боту

Типичные сценарии на Bothost: бот принимает Word-шаблон и отдаёт PDF клиенту; автоматическая выдача договоров и актов в Telegram; конвертация загруженных документов без отдельного сервера. Всё выполняется внутри контейнера вашего бота — достаточно добавить `Dockerfile` в репозиторий и включить опцию **«Использовать собственный Dockerfile»** при [создании бота](https://bothost.ru/create-bot.php).

---

## См. также

- [Кастомный Dockerfile](custom-dockerfile) — как использовать собственный Dockerfile
- [Установка библиотек: Python, Java и Go](installing-libraries) — стандартные зависимости
- [Хранение базы данных](database-storage) — сохранение файлов между деплоями
- [FAQ](faq) — частые вопросы по деплою
