У инженеров, которые проектируют электронные устройства, документация в виде PDF пользуется большой популярностью. Вспомним, к примеру, даташиты к электронным компонентам. Поэтому и наши САПР поставляются с комплектом PDF-файлов, которые рассказывают про особенности установки и эксплуатации. Долгое время документация выпускалась только так: вместе с каждым релизом продукта в виде набора PDF. Это было устроено не из соображений удобства, а в силу ограничений самого процесса, и со временем эти ограничения стали ощутимы.
В этой статье мы расскажем, как развивали систему документации, сохранив за техническими писателями привычный инструмент, какие трудности возникли с производительностью генератора сайта и как в итоге появился портал docs.eremex.ru. При этом привычный инженерам формат PDF мы сохранили: новый портал не заменяет его, а дополняет, и документация по-прежнему доступна в виде файлов для тех, кому так удобнее.
Как было: документация как часть релиза, а не как сервис
Help&Manual представляет собой нишевый, но довольно популярный среди технических писателей инструмент для авторинга: WYSIWYG-редактор, единый проект, экспорт в разные форматы. Мы использовали его много лет и на выходе получали документацию в виде набора PDF-файлов, по одному или нескольким файлам на продукт.
Формат, который десять лет назад выглядел разумным выбором, со временем начал создавать всё больше проблем:
Поиск внутри PDF неудобен. Стандартный поиск по Ctrl+F работает только внутри одного файла и плохо справляется даже с этим, особенно когда документ разрастается до сотен страниц.
PDF оставался невидимым для поисковых систем и нейросетей. Пользователь, искавший решение проблемы с нашим продуктом, не находил наших же документов: поисковая выдача показывала форумы и сторонние обсуждения. По той же причине ни один AI-ассистент не располагал сведениями о наших продуктах, поскольку содержимое статичных PDF-файлов поисковые системы индексируют неохотно.
Документация обновлялась только вместе с релизом продукта. Процесс был жёстко связан: до релиза изменения в документацию не вносились, после релиза она оставалась неизменной до следующего выпуска. Если ошибку в статье обнаруживали через неделю после выхода версии, исправление откладывалось на месяцы.
Стало очевидно, что проблема не в Help&Manual как редакторе: писатели к нему привыкли, и переучивать их не было необходимости. Проблема состояла в том, каким образом контент превращался в готовую документацию и доходил до пользователя.
Шаг первый: автоматический выход из Help&Manual
Главным условием было сохранить процесс работы технических писателей в неизменном виде. Help&Manual хранит каждую статью в виде XML-файла, а значит, контент можно трансформировать программно, без участия человека.
Так появился конвертер, представляющий собой консольное приложение на .NET Core, которое мы написали с использованием XSLT-трансформаций. На входе он принимает XML-файлы Help&Manual, на выходе формирует Markdown. Перенос всех статей оказался полностью автоматическим: ни одна из более чем двух тысяч статей не переписывалась вручную.
Сейчас портал насчитывает около двух с половиной тысяч статей, и все они продолжают создаваться и обновляться в прежнем редакторе.
Для сборки сайта из получившегося Markdown был выбран MkDocs, на тот момент наиболее очевидный и проверенный вариант для документации в формате docs-as-code. Некоторое время эта схема работала исправно.
Как устроен конвертер изнутри
Рассмотрим техническую сторону подробнее.
Запуск XSLT из C#
XSLT-файл загружается из ресурсов сборки, после чего трансформация выполняется через XslCompiledTransform, который компилирует XSLT в байт-код при загрузке, что обеспечивает высокую скорость при обработке большого количества файлов. Каждый XML-файл из Help&Manual читается через XmlReader и записывается через XmlWriter в кодировке UTF-8 без BOM. Последнее существенно: MkDocs и Zensical чувствительны к наличию BOM в файлах.
XslCompiledTransform transformer = new XslCompiledTransform(); transformer.Load(xsltFile); var utf8NoBom = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false); XmlWriterSettings settings = new XmlWriterSettings { ConformanceLevel = ConformanceLevel.Fragment, OmitXmlDeclaration = true, Encoding = utf8NoBom }; using (XmlReader xmlReader = XmlReader.Create(stringReader)) using (XmlWriter writer = XmlWriter.Create(targetFilePath, settings)) { transformer.Transform(xmlReader, CreateArguments(...), writer); }
Extension-объекты: связь между C# и XSLT
Чистый XSLT 1.0 не хранит состояние между вызовами шаблонов, а нам требовалась сквозная нумерация рисунков и таблиц по всей статье. Решением стали extension-объекты, то есть обычные C#-классы, которые регистрируются в XsltArgumentList и становятся доступны из XSLT по пространству имён.
private static XsltArgumentList CreateArguments(...) { XsltArgumentList args = new XsltArgumentList(); // Счётчик номеров рисунков MutableCounter imageCounter = new MutableCounter(); args.AddExtensionObject("urn:xslt-extensions", imageCounter); // Счётчик номеров таблиц MutableCounter tablesCounter = new MutableCounter(); args.AddExtensionObject("urn:xslt-extensions-tables", tablesCounter); // Транслитератор имён файлов рисунков RussianToEnglishConverter rus = new RussianToEnglishConverter(); rus.Prefix = imagesPrefix; // префикс продукта, например "index" args.AddExtensionObject("urn:xslt-extensions-images", rus); // Конвертер имён топиков и резолвер ссылок TopicNameconverter topic = new TopicNameconverter(sourceDir, dirs); args.AddExtensionObject("urn:xslt-extensions-files", topic); return args; }
В XSLT эти объекты объявляются через xmlns и используются как обычные функции:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:imagecounter="urn:xslt-extensions" xmlns:tablecounter="urn:xslt-extensions-tables" xmlns:images="urn:xslt-extensions-images" xmlns:files="urn:xslt-extensions-files" exclude-result-prefixes="imagecounter tablecounter images files">
Нумерация рисунков
Это наиболее показательная часть с точки зрения взаимодействия C# и XSLT. Help&Manual использует собственный плейсхолдер <%HMFIGURECOUNTER%> в подписях к рисункам. При конвертации его необходимо заменить на порядковый номер.
Класс MutableCounter намеренно сделан простым: он хранит счётчик и предоставляет два метода.
public class MutableCounter { public int Value { get; set; } = 1; public int Increment() { Value++; return Value; } public int GetValue() => Value; }
В XSLT шаблон обработки рисунка выглядит следующим образом:
<xsl:template match="image"> <!-- Сначала получаем текущее значение счётчика без инкремента, чтобы определить, есть ли у рисунка подпись --> <xsl:variable name="currentimagetitle"> <xsl:value-of select="files:ReplaceCounters(caption, imagecounter:GetValue())"/> </xsl:variable> <xsl:variable name="imagetarget"> <xsl:value-of select="concat($imagesPath, images:Convert(@src))"/> </xsl:variable> <xsl:choose> <!-- SVG-рисунки обрабатываются отдельно, вставляются как HTML-тег --> <xsl:when test="contains($imagetarget, 'svg')"> <image src="{$imagetarget}"/> </xsl:when> <!-- Рисунок с подписью: инкрементируем счётчик и формируем figure --> <xsl:when test="$currentimagetitle != ''"> <xsl:variable name="imagetitle"> <xsl:value-of select="files:ReplaceCounters(caption, imagecounter:Increment())"/> </xsl:variable> <xsl:text disable-output-escaping="yes"><figure></xsl:text> <img src="{$imagetarget}" alt="{$imagetitle}"/> <xsl:text disable-output-escaping="yes"><figcaption></xsl:text> <xsl:value-of select="$imagetitle"/> <xsl:text disable-output-escaping="yes"></figcaption></figure></xsl:text> </xsl:when> <!-- Рисунок без подписи: простой Markdown-синтаксис --> <xsl:otherwise> <xsl:value-of select="concat('')"/> </xsl:otherwise> </xsl:choose> </xsl:template>
Логика построена на двух методах счётчика. Сначала вызывается imagecounter:GetValue(), чтобы проверить наличие подписи, не изменяя счётчик. Если подпись есть, вызывается imagecounter:Increment(), который увеличивает значение и возвращает новое. Благодаря этому счётчик растёт только для пронумерованных рисунков.
Транслитерация имён файлов рисунков
Help&Manual допускает имена файлов рисунков на русском языке, что недопустимо в URL. Поэтому все имена файлов при копировании проходят через транслитератор:
// Кириллица в латиницу, пробелы в подчёркивания // "Окно настроек.png" в "indexokno_nastroek.png" var targetFileName = RussianToEnglishConverter.ConvertWithPrefix( Path.GetFileName(imageFile), databaseName.Name // префикс продукта, например "index" для Delta Design );
Префикс продукта добавляется намеренно. У разных продуктов могут встречаться одноимённые файлы рисунков, и без префикса они перезаписывали бы друг друга.
Отдельные шаблоны
Заголовок статьи преобразуется в Markdown-frontmatter с YAML и заголовок уровня #:
<xsl:template match="header"> <xsl:text>--- </xsl:text> <xsl:text>search: </xsl:text> <xsl:text> exclude: true </xsl:text> <xsl:text>--- </xsl:text> <xsl:value-of select="concat('# ', normalize-space(para/text))"/> <xsl:text> </xsl:text> </xsl:template>
Ссылки между статьями преобразуются в реальные пути к Markdown-файлам. Help&Manual хранит ссылки как пути к XML-файлам, а конвертер транслирует их в пути с расширением .md через метод TopicNameconverter.Convert(), который читает элемент <title> из XML-файла и транслитерирует его в имя файла:
<xsl:template match="link"> <xsl:variable name="linkTarget"> <xsl:when test="@href[string-length() > 0]"> <xsl:value-of select="files:Convert(@href)"/> <xsl:if test="not(contains(@href, '.'))"> <xsl:text>.md</xsl:text> </xsl:if> </xsl:when> <!-- якорные ссылки внутри статьи --> <xsl:when test="@anchor[string-length() > 0]"> <xsl:text>#</xsl:text> <xsl:value-of select="@anchor"/> </xsl:when> </xsl:variable> <xsl:value-of select="concat('[', $linkTitle, '](', $linkTarget, ')')"/> </xsl:template>
Подсказки (tips, warnings, notes) обрабатываются одним из самых содержательных шаблонов. В Help&Manual они оформляются как таблица из двух столбцов, где в первом столбце расположена иконка (warning.png, info.png, idea.png). Конвертер распознаёт этот паттерн по структуре таблицы и преобразует его в синтаксис admonition-блоков Zensical:
<xsl:template match="table[ @colcount='2' and @rowcount='1' and not(thead) and tr/td[1]/para/image/@src != '' ]"> <xsl:variable name="hinttype" select="substring-before(tr/td[1]/para/image/@src, '.')"/> <!-- "warning.png" в "warning", далее в "!!! warning" --> <xsl:value-of select="concat('!!! ', $hinttype, ' ', files:Localize($hinttype))"/> <xsl:text>

 </xsl:text> <xsl:apply-templates select="tr/td[2]"/> </xsl:template>
Фильтрация статей по статусу
Конвертер обрабатывает только статьи со статусом «Завершен» в атрибуте корневого XML-элемента. Это позволяет техническим писателям держать черновики в том же репозитории и в том же проекте Help&Manual: на сайт они не попадут до тех пор, пока статус не будет выставлен.
private static bool AllowProcessXML(string file, string xmlContent) { var status = TopicNameconverter.ExtractStatus(xmlContent); return status == "Завершен"; }
Шаг второй: пределы производительности MkDocs
Документация Eremex охватывает не один продукт, а целую линейку: Delta Design, SimPCB Lite, Enterprise Server, Simtera IC, DeltaCAM. В сумме это около двух с половиной тысяч статей. На таком объёме MkDocs начал заметно замедляться: полная сборка сайта занимала более пяти минут.
Для CI, где сборка запускается на каждый коммит, пять минут составляют существенную задержку. Каждое изменение одной строки в одной статье означало пятиминутное ожидание перед тем, как результат становился доступен на внутреннем сайте.
В качестве альтернативы был выбран Zensical, более новый статический генератор документации. Поскольку промежуточным форматом уже служил Markdown, переход с одного генератора на другой не потребовал повторной миграции контента, ограничившись перенастройкой сборки. Результат оказался следующим:
сборка сайта сократилась с приблизительно пяти минут до приблизительно одной минуты;
полнотекстовый поиск на сайте стал быстрее и точнее, чем у MkDocs.
Как это работает сейчас
Итоговая схема получилась гибридной, и в этом её основное достоинство. Технические писатели по-прежнему работают в привычном Help&Manual, менять редактор им не пришлось. Изменилось то, что происходит с контентом после сохранения.
Единственное, чему потребовалось обучить писателей, это работа с Git. Они фиксируют изменения в репозитории, и далее процесс выполняется автоматически:
По коммиту запускается CI.
Конвертер на .NET Core и XSLT преобразует XML-файлы Help&Manual в Markdown.
Zensical собирает из Markdown статический сайт.
CI собирает Docker-образ со статическим сайтом и публикует его в GitLab Container Registry.
Watchtower на внутреннем сервере обнаруживает новый образ и автоматически перезапускает контейнер.
Обновлённая версия становится доступна на внутреннем сайте документации.
На внутреннем сайте команда проверяет новые и изменённые статьи, убеждаясь, что контент отображается корректно, конвертация прошла без ошибок, а форматирование соответствует задуманному.
Публичная версия docs.eremex.ru обновляется вручную, синхронно с релизом продукта. Это осознанное решение: выпуск продукта и выпуск документации к нему остаются согласованным событием, однако теперь публикация представляет собой полностью контролируемый шаг, а не сжатую по срокам пересборку PDF.
Технический писатель │ пишет в Help&Manual ▼ XML-файлы (Help&Manual) │ git commit ▼ CI (GitLab) ├─ XSLT-конвертер: XML в Markdown ├─ Zensical: Markdown в статический сайт (~1 мин) └─ Docker build, push в GitLab Container Registry ▼ GitLab Container Registry │ Watchtower опрашивает раз в минуту ▼ Внутренний сервер (Docker, Watchtower) │ автоматический pull и restart контейнера ▼ Внутренний сайт документации │ проверка командой ▼ Публикация вручную, синхронно с релизом продукта ▼ docs.eremex.ru
Развёртывание через Docker и Watchtower
Для автоматического обновления внутреннего сайта не потребовалось писать deployment-скрипты и настраивать SSH-доступ с CI на сервер. Вместо этого применяется Watchtower, служба, которая отслеживает обновления Docker-образов в реестре и перезапускает контейнеры при появлении новой версии.
Вся инфраструктура сервера описана в одном файле docker-compose.yml:
services: docs.app: image: registry.gitlab.eremex.ru/eremex/docs.app container_name: docs.app restart: always watchtower: image: containrrr/watchtower container_name: watchtower volumes: - /var/run/docker.sock:/var/run/docker.sock environment: - WATCHTOWER_POLL_INTERVAL=60 # проверять обновления раз в минуту command: docs.app --label-enable restart: unless-stopped
Конфигурация состоит из двух сервисов, каждый из которых выполняет одну задачу.
docs.app содержит статический сайт документации. CI собирает этот контейнер при каждом коммите и публикует его в GitLab Container Registry.
watchtower обеспечивает автоматическое обновление. Он монтирует Docker-сокет (/var/run/docker.sock), что позволяет ему управлять другими контейнерами от имени хоста. Раз в минуту, согласно параметру WATCHTOWER_POLL_INTERVAL, Watchtower проверяет реестр. Если образ docs.app обновился, служба загружает новую версию и перезапускает контейнер. Такой подход не требует ни вебхуков, ни SSH, ни deployment-скрипта на сервере.
В результате вся цепочка от коммита в репозиторий до обновления внутреннего сайта не требует ручного вмешательства. CI собирает образ и публикует его в реестре, Watchtower загружает образ, контейнер перезапускается, и команда получает доступ к актуальной версии документации.
Что изменилось
Измеримых показателей у нас немного, однако изменения ощутимы и для команды, и для пользователей.
Скорость сборки. Пять минут на MkDocs против одной минуты на Zensical составляют пятикратное ускорение, и при объёме около двух с половиной тысяч статей эта разница проявляется на каждом коммите.
Документация стала доступна мгновенно, с любого устройства и из любой точки мира. Прежде требовалось найти нужный PDF, загрузить его и открыть на компьютере. Теперь пользователь открывает ссылку с телефона, ноутбука или любого браузера и сразу получает актуальную статью, без загрузки файлов. При этом сам формат PDF остался доступен для тех, кто к нему привык.
Появились полноценные перекрёстные ссылки. Статьи документации перестали существовать как изолированные файлы. Из одной статьи можно сослаться на другую и провести читателя по связанным темам.
Документация вошла в поисковую выдачу и в ответы нейросетей. Контент, прежде недоступный для Google и AI-ассистентов, теперь индексируется как обычный веб-сайт. На практике это означает, что AI-ассистенты дают более содержательные и точные ответы по нашим продуктам, поскольку получили доступ к первоисточнику, а не только к фрагментам обсуждений на сторонних форумах.
Появилась аналитика. Прежде у нас не было способа оценить, какие статьи документации читают пользователи. Теперь мы видим востребованность конкретных статей и можем направлять усилия команды туда, где они принесут наибольшую пользу, вместо равномерного распределения по всем разделам.
Что дальше: контекстная справка в Delta Design
Новая система документации открыла возможность, недоступную при работе с PDF, а именно контекстную справку непосредственно внутри Delta Design.
Замысел состоит в следующем. Каждая форма, диалог и панель в приложении получает уникальный идентификатор, который связывается со статьёй в документации. Пользователь нажимает F1 в любой части интерфейса и получает не оглавление всей справки, а именно ту страницу, которая описывает текущий элемент на экране.
С набором PDF-файлов такое решение было неосуществимо: у отдельных тем не было ни постоянных URL, ни механизма точечной навигации внутри файла. Сайт на основе Markdown, где каждой статье соответствует отдельная страница, предоставляет иные возможности: у каждой темы есть постоянный адрес, и привязать к нему идентификатор формы технически несложно.
Вторая часть замысла предполагает навигацию в обратном направлении, из документации в приложение. Планируется поддержка специальной схемы ссылок:
deltadesign://options deltadesign://project/settings
Такая ссылка в статье документации при нажатии будет открывать соответствующее окно или диалог в запущенном экземпляре Delta Design. Пользователь, читающий статью о настройке экспорта, сможет открыть нужное окно нажатием на ссылку в тексте, не разыскивая соответствующий пункт меню самостоятельно.
Подобное решение преобразует документацию из обособленного справочника в двунаправленный интерфейс между пользователем и продуктом: приложение направляет пользователя к нужному разделу документации, а документация возвращает его к нужной части приложения.
Пока это планы. Реализуемыми их делает то обстоятельство, что документация теперь существует как полноценный веб-сайт с постоянными URL и открытой структурой.
Итоги
Основной вывод из нашего опыта состоит в том, что для модернизации публикации документации не обязательно менять инструмент, в котором она создаётся. Технические писатели остались в привычном для них редакторе Help&Manual, тогда как преобразования произошли на уровне инфраструктуры: автоматический конвертер вместо ручного экспорта, Git вместо пересылки файлов, CI вместо ручной сборки, Docker с Watchtower вместо развёртывания по SSH, современный статический генератор вместо устаревшего механизма выпуска PDF.
Второй вывод заключается в том, что выбор инструмента для самой трансформации также не является окончательным. Мы перешли с Help&Manual на MkDocs, считая этот этап завершающим, однако на объёме более двух тысяч статей MkDocs достиг своих пределов. Переход на Zensical потребовался не вследствие ошибки в начале пути, а потому, что требования возросли вместе с объёмом документации. Решение, оптимальное для двухсот статей, не обязано оставаться таковым для двух с половиной тысяч.
Комментарии (8)

xtraroman Автор
25.06.2026 12:12Вы же «перестраховались» на все тысячу процентов.
Спасибо, что обратили внимание. Мы проверим этот момент с коллегами.
Я для устранения дефектов распознавания использую собственную (неопубликованную) программу «МедиаГекст».
Скриншоты выглядят отлично. Видно, что проделана большая работа.
Если не считать непонятную задержку при рендеринге фрагментов статей в HTML-формате. Это проблемы сервера?
В статье я говорил про затраты времени на приготовление всего сайта. Имеем на входе набор XML-файлов Help&Manual, а на выходе должен получиться сайт. Этот процесс состоит из нескольких стадий (как я это понимаю):
XSLT-преобразование XML → MD.
MkDocs / Zensical готовят из большого набора MD-файлов HTML-файлы с учётом заданных стилей и шаблонов, добавляется код Яндекс.Метрики в каждую страницу.
Кроме собственно контента сайта в виде HTML, надо правильно приготовить навигационную часть сайта (то, что будет показываться в левой колонке).
Есть ещё стадия приготовления индекса для полноценного поиска по сайту.
Все эти стадии требуют полного обхода содержимого статей, и поэтому сборка сайта занимает некоторое время, если у вас приличное количество материала.

Emelian
25.06.2026 12:12Скриншоты выглядят отлично. Видно, что проделана большая работа.
Спасибо! Надеюсь, после оптимизации программы, как дойдут до этого руки, опубликовать её в опенсорсе.
Все эти стадии требуют полного обхода содержимого статей, и поэтому сборка сайта занимает некоторое время, если у вас приличное количество материала.
Не уверен, что вы организовали все оптимально. Возьмите любой сайт, где отображаются pdf-страницы (как правило, с помощью PdfToHtml) целиком, а не фрагментами, как у вас. Они рендерятся достаточно быстро, хотя html-кода там не меряно. Да и «навигационная часть сайта (то, что будет показываться в левой колонке)» там выглядит более симпатично, чем у вас. Т.е., все это – уже давно существующий опенсорсный функционал.
А то, что у вас много внутренней работы на сайте, так и оставьте ее внутренней, а не выносите наружу. Ну, а если вам влом делать оптимизацию вашего сайта, то кто вас заставит? По своему длительному программистскому опыту, на производственном предприятии, убедился, что какой бы плохой ни была программа, всегда найдутся пользователи, у которых к ней не будет никаких претензий.
Надеюсь, что таких пользователей вашего сайта – большинство!
Emelian
Ну, если я правильно понял, имея оригинальный текст статьи в xml (либо html), то, преобразовать его в pdf или тот же html для сайта не должно быть большой технической проблемой. Тогда непонятно, почему страницы с фрагментами ваших статей обновляются так долго (порядка нескольких секунд)?
Куда интересней задача преобразования цифрового pdf в форматированный html-файл. На самом деле, существуют опенсорс на Гитхабе, типа, PdfToHtml (для непосредственного отображения pdf-страниц в вебе). На его базе также существует масса онлайн-ресурсов, которые преобразуют pdf-страницы в «чистый» html.
Но, как всегда в подобных случаях: «Дьявол кроется в деталях». Подобные html-страницы слишком перегружены информацией, настолько, что приходится делать собственный «велосипед» для получения упрощенного форматирования, например, для целей создания двуязычных книг ради изучения иностранного языка. Вот пример:
Хорошо, что это не ваша книга. У вас простое «использование документа» уже является нарушением. Т.е., вы позволяете скопировать ваш pdf-файл на компьютер, но, как только я это сделал, хотя бы просто любопытства ради (тем более, что вы сами поощряете это), то уже автоматически становлюсь нарушителем, судя по вашему грозному «Руководству Пользователя»? Т.е., ничего нельзя, а что можно то?
xtraroman Автор
У портала документации действительно прописаны некоторые ограничения на использование материалов (https://docs.eremex.ru/legal/). Я не юрист и не могу их комментировать. Если у вас есть идея, относящаяся к нашим статьям, напишите нам. Я уверен, всё можно решить.
Все наши статьи в исходном виде хранятся в XML-файлах Help&Manual, поэтому нам не пришлось возиться с извлечением информации из PDF-файлов. В общем случае это очень сложная задача. Мне встречались PDF-файлы, в которых текст был представлен в виде растрового изображения. Также в некоторых случаях текст в PDF может быть преобразован в набор кривых. Поэтому в общем случае извлечение контента из PDF — это сложная задача, сравнимая по сложности с распознаванием документа. Хорошо, что нам не пришлось этим заниматься.
Emelian
Это не «некоторые ограничения» это абсолютные ограничения! Теоретически, судя по вашей «Правовой информации», вы можете привлечь к ответственности любого, кто просто воспользовался вашей ссылкой и скопировал себе на компьютер любой файл («воспроизведение» и «копирование», как минимум). Более того, если пользователь только зашел на ваш сайт он уже «нарушитель» ибо браузер автоматически скопировал в кэш компьютера вашу html-страницу (содержащую вашу интеллектуальную собственность). Естественно, посмотреть эту html-страницу и, не дай Бог, скопировать оттуда, для своих коммерческих целей, допустим, какой-нибудь скрипт – святотатство! Даже если этот скрипт делает что-то нехорошее на моем компьютере. Тем более, что я его не просил загружаться. Но, все равно виноват? Иначе говоря, сайту – все права, а пользователю – никаких!
Обычно, использование авторской информации для личных целей не запрещают, только коммерческое использование чужих материалов может быть наказуемо. Вы же «перестраховались» на все тысячу процентов.
Сложная? Согласен, сам уже вожусь не первую неделю. Только эта тема мне понравилась, поскольку pdf рендерится не последовательно, как все «нормальные» документы, а в виде произвольно отображаемых прямоугольных областей. Соответственно, если прямоугольники, допустим, A и B, не пересекаются, то результат не зависит от порядка их отображения, т.е. A•B == B•A (коммутативность). Часто это тупо нарушает линейную последовательность текста. Во избежание чего приходится сортировать текст (уровня символов) по их координатам. Но и это не всегда помогает, если текст содержит подстрочные и надстрочные символы (которые оформляются прямоугольниками для тех же самых шрифтов, но меньшего размера при непредсказуемом порядке следования).
Что касается растровых изображений, то это просто прямоугольники с графикой. В принципе, как вы пишите, pdf может состоять только из них. Но тогда можно использовать библиотеки распознавания символов в изображениях, в том же Питоне (вроде Тэзэракта). Да, это ненадежный вариант. Я для устранения дефектов распознавания использую собственную (неопубликованную) программу «МедиаГекст» (для работы с видео, звуком и обычными изображениями, например, извлеченными из pdf/djvu-файлов):
Это что-то вроде векторной графики. Обычно ее немного и проще распознать вручную либо вообще игнорировать, как и обычные изображения, в упомянутой мной книге по французской грамматике.
В вашем случае, действительно все проще, если не считать непонятную задержку при рендеринге фрагментов статей в html-формате. Это проблемы сервера?
PereslavlFoto
Пишу. Есть идея.
Везде, где у вас написано “нельзя”, напишите “можно”.
Где у вас “запрещено”, напишите “разрешаем”.
Это очень просто. Попробуйте сами.
xtraroman Автор
Какую именно проблему нужно решить? Вы хотите портал с нашей документацией разместить в закрытой сети предприятия?
PereslavlFoto
Проблема хорошо обозначена выше в комментариях. Вы слишком многое запретили.