Сделали и забыли — работает же. Пока не случилась проблема со шрифтами. Снова намучились и снова решили. Но что примечательно — с тех пор готовой инструкции по генерации в PDF на просторах интернета не появилось. Поэтому выкладываю нашу. Внутри алгоритм с комментариями и файлами шаблона, особенностями ReST для LaTeX, которые мы собрали опытным путём.
Статья для тех, кто уже использует Sphinx, но имеет проблемы с LaTeX или PDF. Если вы только рассматривает Sphinx как инструмент документирования, будет полезно представлять, как готовить и подавать документацию в этих форматах.
Сразу скажу, почему нам не подошёл ReadTheDocs, где уже предусмотрена генерация PDF:
- Наша документация должна размещаться во внутренней сети
- Нужно иметь возможность выгрузить в PDF только часть документации (папку)
- Генерация должна идти через LaTeX, шаблон которого в свою очередь мы хотели менять под разные задачи и под корпоративный стиль
Зачем LaTeX
Для простейшего PDF подойдёт rst2pdf. Но нам не подойдет простейший PDF, потому что нужно делать по красоте, использовать стилизованные шаблоны. Поэтому используем LaTeX, как промежуточный формат.
Он позволяет решить массу вопросов с нумерацией страниц, оглавлением, типографикой, переносом слов, сносками, таблицами, перекрестными ссылками, иллюстрациями и т.д. Структуру документа в LaTeX можно отдельно стилизовать, одна и та же структура данных может выводиться в разных форматах, с различным оформлением. Это управляется стилями LaTeX.
Стилизованные PDF нам нужны для формирования выходной документации для клиента: пользовательских инструкций, отчетов, коммерческих предложений, простых презентаций.
Приступим
Спасибо Андрею Безрукову (@aur), который собрал первичную информацию и проверил базовые вещи.
1. Подготовка
Python и Sphinx уже должны стоять на сервере (у нас Debian), подготовлена документация в reStructuredText, генерация которой проверена на формате html.
Ставим пакеты для LaTeX. Пример:
sudo apt-get install texmaker gummi texlive texlive-full texlive-latex-recommended latexdraw intltool-debian lacheck libgtksourceview2.0-0 libgtksourceview2.0-common lmodern luatex po-debconf tex-common texlive-binaries texlive-extra-utils texlive-latex-base texlive-latex-base-doc texlive-luatex texlive-xetex texlive-lang-cyrillic texlive-fonts-extra texlive-science texlive-latex-extra texlive-pstricks
В конфиге документации conf.py добавляем/раскомменитруем параметр latex_documents:
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'yourdoc.tex', u'DocName', u'YourName', 'manual'),
]
Здесь же находятся другие основные настройки для LaTeX: размер страницы, шрифт, преамбула и т.д.
2. Генерация LaTeX
Выполняем команду:
sphinx-build -b latex doc/source/ doc/latex/
где source — это папка с корневым файлом index.rst, а latex — папка назначения.
Генерируется сразу вся документация, а не отдельные файлы. В результате в корне папки latex появится пачка файлов, среди которых файл .tex — главный файл документации в формате latex. Пример содержимого папки на этом этапе в архиве latex_default.zip.
3. Изменения в latex (файл .tex)
Если нужно изменить базовую верстку LaTeX, и основных настроек в conf.py недостаточно, меняем сам шаблон документа, его разметку и стили.
В файле .tex есть преамбула (до \begin{document}), где подключаются пакеты, определяются переменные, могут описываться стили и т.д. Здесь подключаем дополнительные пакеты, которые нам нужны.
Примеры
\usepackage{multicol}
\usepackage{tikz}
\usepackage[screen,margin=0.8in]{geometry}
\usepackage{geometry}
\geometry{landscape}
В файле .tex находится директива \maketitle, которая создаёт стандартный титульный лист, используя информацию о названии документа (\title), авторе (\author) и дате написания текста (\date).
Можем заменить \maketitle на свой шаблон. Мы для себя создали отдельный файл TitlePage.tex — шаблон главной страницы, на который заменяем \maketitle. Для разных документов используем различные шаблоны оформления.
Примеры
\tableofcontents
\phantomsection\label{index::doc}
\noindent Copyright \copyright\ [COPYRIGHT]\\
\noindent \textsc{[COPYRIGHT_2]}\\ % Publisher
\noindent \textsc{\url{https://netoria.ru}}\\ % URL
\noindent [RIGHT_INFO] \\ % License information
\noindent \textit{Дата публикации: [DOC_DAY]}
\newpage
где [COPYRIGHT], [RIGHT_INFO] и пр. заменяем на нужный контент.В конец .tex-файла тоже можно добавить какой-либо шаблон-завершение. Так мы вставляем свой лого и контакты, а иногда и внешний PDF-файл рекламного характера.
\newpage
\textcolor{red}{\noindent\makebox[\linewidth]{\rule{\textwidth}{0.4pt}}}\par\vspace{0.5cm}
\begin{figure}[h]
\begin{center}
\begin{minipage}[h]{0.3\linewidth}
\includegraphics[width=0.8\linewidth]{logo_contact.png}
\end{minipage}
\hfill
\begin{minipage}[h]{0.6\linewidth}
{ООО Нетория}\par{+7 (3452) 692-242}\par{netoria.ru}\par{info@netoria.ru}
\end{minipage}
\end{center}
\end{figure}
\par\vspace{0.5cm}
\textcolor{red}{\noindent\makebox[\linewidth]{\rule{\textwidth}{0.4pt}}}
\includepdf[pages={1,2}]{advertising.pdf}
\renewcommand{\indexname}{Алфавитный указатель}
\printindex
\end{document}
Копируем в папку latex наш логотип logo.png, т.к. он используется у нас в шаблоне титульной страницы.
4. Генерация pdf
Выполняем первую генерацию документа PDF командой:
pdflatex yourdoc.tex
В папке latex появляются файлы:
- .aux — информация о перекрёстных ссылках
- .toc — файл оглавления (table of contents)
- .log — лог генерации PDF
- .pdf — PDF-файл. Но в нём ещё нет оглавления
Выполняем генерацию и стилизацию оглавления командой:
makeindex yourdoc.idx
Выполняем повторную и финальную генерацию PDF:
pdflatex yourdoc.tex
В той же папке появляется финальный файл PDF. Пример содержимого папки на этом этапе в архиве latex_modified.zip.
Если не проделывать промежуточных генераций, то на выходе будет документ без оглавления. Оглавление toctree корневого файла становится оглавлением книги PDF. Оглавление contents каждого из файлов становится оглавлением каждой главы. Все ссылки оглавления, внутренние и внешние ссылки ReST корректно переносятся.
Если в ReST есть ошибки (отсутствуют изображения, некорректный синтаксис и подобное) — то при генерации PDF команда pdflatex тоже будет выдавать ошибки и ожидать действий пользователя (Enter — пропустить и продолжить, H — исправить автоматически, X — оборвать генерацию). Чтобы отключить этот интерактив, команду нужно вызвать с параметром, который оборвет процесс при первой же ошибке:
pdflatex -halt-on-error yourdoc.tex
Требования к ReST для генерации LaTeX
Для html версии эти требования являются некритичным, документация всё равно будет сформирована. Но для LaTeX это фатально. Список собран опытным путём.
- Должны физически существовать картинки, которые используются в тексте.
- По умолчанию максимальная вложенность маркированных и нумерованных списков: 3. Если больше, будет ошибка (“LaTeX Error: Too deeply nested”). Решается это так, проверено.
- Листинги (исходный код): для длинных строк ставьте переносы, автоматически это не произойдёт. Иначе строки будут выходить за пределы страницы, будут “обрезаны”.
- При копировании текста откуда-то, удалите спецсимволы, если они есть (смайлы, спецсимволы html).
- Лучше, чтобы не было ошибок синтаксиса ReST.
Ещё, иногда страницы разбиваются неадекватно, если есть картинки, таблицы, блоки предупреждений. Тогда в файле rst придётся расставлять разрыв страницы для latex:
.. raw:: latex
\newpage
Проблема со шрифтами
При возникновении проблемы первым делом смотрите логи — причины могут быть разными. У нас было 2 ситуации. Добавляйте в комментариях свои.
В один прекрасный день перестала работать генерация. Связали это с обновлением сервера. Посмотрели логи — sphinx стал искать шрифты в другой папке. Решили через mount папки шрифтов, прописал это в автозагрузке сервера.
Другой случай. Для LaTeX нужны шрифты в формате tfm. При установке шрифтов на сервер они должны генериться автоматически. Почему-то это работает не всегда. Решили это ручным запуском генерации (команда mktextfm <название шрифта>) для таких шрифтов.
Скачать бесплатно и без sms
- Пример исходной документации в rst: Демо_генерации_PDF.tar.gz
- Пример документации в LaTeX до модификации: latex_default.zip
- Пример документации после модификации LaTeX и результатный PDF: latex_modified.zip
- Примеры шаблонов LaTeX: www.latextemplates.com Верстка сложного шаблона — это пожиратель времени, если у вас нет в этом опыта — в условиях ограниченного времени лучше у кого-то заказать.
Надеюсь, это поможет вам сэкономить несколько часов или дней при решении подобной задачи.
Об ошибках прошу сообщать в личку.
Комментарии (9)
Ivanq
08.05.2017 17:58+1Ставим пакеты для LaTeX. Пример:
sudo apt-get install texmaker gummi texlive texlive-full texlive-latex-recommended latexdraw intltool-debian lacheck libgtksourceview2.0-0 libgtksourceview2.0-common lmodern luatex po-debconf tex-common texlive-binaries texlive-extra-utils texlive-latex-base texlive-latex-base-doc texlive-luatex texlive-xetex texlive-lang-cyrillic texlive-fonts-extra texlive-science texlive-latex-extra texlive-pstricks
pantlmn
09.05.2017 12:28Ещё, иногда страницы разбиваются неадекватно, если есть картинки, таблицы, блоки предупреждений.
А они ставятся как плавающие объекты через
или прямо брутально встраиваются в текст?\begin{figure|table}
oren
09.05.2017 12:57Разбивание страниц, это вообще глобальная проблема при переносе «потоковых» данных в многостраничные.
Но именно в LaTeX эту проблему можно почти полностью решить.
Планирую как-нибудь на хабре написать о своём способе, где я для этого немного переписал пакет longtable.
smarteq
10.05.2017 09:05+1От души жму руку Вам за отвагу!
Дело все в том, что примерно год я шел к этому же решению, правда из php. Но в последний момент свернул в сторону… LibreOffice. Лично мне ваше решение намного более симпатично потому что мое решение в плане технической крутизны вызывает некоторый скепсис, и возможна нестабильность, но я ниасилил (по ряду причин, главным образом сроки и количество попутно решаемых задач), а Вы да — за это и жму руку.
P.S. Ну и напоследок мой вариант:
1. Делаем примерный шаблон в LibreOffice, переименовываем в .zip.
2. Подменяем содержимое content.xml и settings.xml (там колонтитулы)
3. Запаковываем обратно и сохраняем как odt
4. libreoffice --headless --convert-to pdf:writer_pdf_Export file.odtlencom
11.05.2017 19:20+1Спасибо, Никита :) По пути мы съели несколько кактусов, но тем слаще победа.
Давайте обратно на светлую сторону)
oren
Если использовать XeTeX вместо pdfTeX, то можно использовать обычные шрифты (OpenType).