Трагичная история знакомства с poppler

    …Или как мы писали пилот приложения для ОС Sailfish с использованием poppler.

    Год начался с занятной задачи — нашей команде нужно было за короткий срок собрать пилот приложения «Мобильное рабочее место руководителя» на ОС Sailfish. По сути, это мобильный клиент СЭД, т.е. он предназначен для работы с документами. Ну и конечно же, для работы с документами необходим pdf-reader. Но оказалось, что заставить его работать гладко не так-то просто. Но мы, можно сказать, справились (для прототипа, конечно). Как? Читайте под катом.

    image

    Из хорошего могу сказать, что pdf-reader, встроенный в операционную систему, — это просто замечательно, не нужно отдельно собирать. И «Аврора» (вроде как, это будущее «русское» название для труднопроизносимой «Sailfish Mobile OS Rus») этим похвастаться может, за что ей большое спасибо. Но всё-таки написать быстрое решение оказалось не так просто.

    Poppler — библиотека для рендеринга pdf, встроенная в Sailfish, собственно, потому она и была выбрана для наших тёмных целей. Но только для написания прототипа, ибо лицензия GPL не позволит в будущем выпускать на нём коммерческий продукт. Да и, немного потрогав её, прихожу к выводу, что наверняка есть более удобные решения, но об этом чуть позже.

    Рассказать хочется главным образом о двух основных проблемах, с которыми я столкнулась, пытаясь хоть что-то выжать из poppler в сжатые сроки. Предлагаю посмотреть видео, демонстрирующее работу приложения, которое получилось, прежде чем читать моё нытье.


    Проблема номер раз


    Видите красивую карусель? Это такой способ отображения документов по папкам — интуитивно понятный и простой для пользователя, позволяет быстро просматривать документы, детали по нему, прежде чем переходить непосредственно к чтению документа и согласованию. Нужен он для того, чтобы важные министры, подписывая свои очень важные документы, могли взор свой услаждать PathView.

    PathView — замечательный инструмент, можно кучу всякой красоты понаделать. Но наша проблема заключается в делегате.

    Рисовать первую страницу документа (превью документа на главном экране) в онлайн режиме, используя poppler, — идея так себе, ибо папки не кэшируются, и переход между ними начинает невероятно висеть, poppler рисует медленно. Точнее рендерит, рисует, конечно, QPainter.

    Проблема решается просто, но совсем не изящно: рендерим превью при запуске приложения, сохраняем на устройство картинку и в итоге рисуем через QImage в делегате. И, честно говоря, как переписать это в более изящный вид, я пока не придумала.

    Проблема номер два


    Если пытаться нарисовать документ большого размера весь разом (страница, отображающая контент документа), он мало того, что делает это очень долго, так ещё и смазывает картинку. Думала, напутала с размерами, что документ рендерится в картинку маленького размера, а потом растягивает его на заданную величину, но нет, проверила всё по 100 раз. Пыталась делать картинку большего размера — всё то же самое. Да и мажет не как с потерей качества, а скорее, как будто провели рукой по свежим чернилам.

    Это, конечно, решается все одним махом, нужно рисовать не целиком документ, а только текущую страницу и соседние, но не успела ещё этого сделать.

    Итог


    Poppler медленный и странный, но спасибо, что он есть. Сейчас хотим в рамках пилота реализовать графические и текстовые аннотации pdf, поэтому собираюсь переписать все это дело на другой библиотеке, это что-то невероятно мощное на первый взгляд, надеюсь, что заявленная функциональность действительности соответствует.

    Если кто пробовал или знает решение более подходящее, буду максимально признательна за совет.
    Digital Design
    169,00
    Компания
    Поделиться публикацией

    Комментарии 15

      +1
      Qt вроде с pdfium дружит, через QPdfDocument
      +2

      mupdf вроде самая быстрая из opensource библиотек, смотрели в ее сторону?

        0
        Смотрела мельком, кажется, она только читает, а я в надеждах найти что-то, что еще и писать умеет)
          0
          вполне себе пишет
          0

          Честно сказать, код примеров выглядит так будто его писали марсиане, да и документации нормальной нет, как этим вообще пользоваться?

          0
          Попробуйте посмотреть в сторону html. Потом уже генерировать pdf документ.
            0

            Можно ещё в сторону libpodofo посмотреть
            http://podofo.sourceforge.net/about.html

              +1
              а я в надеждах найти что-то, что еще и писать умеет

              Возможно мой опыт будет полезен.


              Мне для виртуального принтера надо преобразовывать PDF-ы — сливать несколько страниц в одну, масштабировать, поворачивать страницы и.т.д.


              Вначале я использовал poppler как для рендеринга, так и для чтения/преобразования PDF-ов. И если с рендерингом все более-менее хорошо, то с обработкой я натерпелся. Poppler имеет 2 API. Один публичный высокоуровневый, но он очень ограничен, по сути только отрисовать страницу и все. И второй низкоуровневый и полузакрытый, на сайте про него не написано, но во всех дистрибутивах есть пакеты с нужными заголовочными файлами. Вот этот API позволяет преобразовывать PDF-ы на уровне объектов. Публичного API мне не хватало, и я решил использовать низкоуровневый, ох и натерпелся я. Этот API очень запутанный и недокументированный. А главное он нестабильный, и может внезапно поменяться в минорной версии библиотеки. Добило меня когда KDE-шники взяли и добавили аргументы в функцию вообще без изменения версии. А т.к. проект опенсорсный, то мне надо поддерживать совместимость с несколькими версиями библиотек (от винтажной в Debian Stable, до модной в ArchLinux)


              Тогда я плюнул, и написал свой велосипед, который позволяет читать менять и сохранять PDF-ы. Рендерю пока через poppler. Смотрел в сторону PDFium — выглядит обещающе, но ее нет в стандартный пакетах, а для вас, для закрытого проекта можно и собрать самому.

                0
                с pdfium все аналогично. В public только минимально рисующий функционал, все остальное спрятано. Зато можно делать почти все что угодно. Я пдф, через pdfium в набор QPainterPath складываю, а затем отрисовываю по мере необходимости. т.е. по существу и SVG и PDF и шрифты внутренне лежат в одном формате, миксуются, а затем сохраняются в результирующий PDF или SVG. Пришлось, правда, помучиться с многофокусными градиентами, но на 98% удалось получить однозначное соответствие. Да, и собирать pdfium из сырцов та еще песня. В Qt в стоке стоит сильно порезанный вариант
                0
                Я пдф, через pdfium в набор QPainterPath складываю, а затем отрисовываю по мере необходимости.

                Не совсем понял, отдельные страницы складываете в QPainterPath, или куски одной страницы?
                Если страницы целиком, то у меня немного другой подход. У меня минимальный квант, это отдельный PDF-ный объект. Я работаю с PDF на уровне исходного текстового документа. Т.е. перенумеровываю объекты в PDF-е, меняю тип пдфной страницы на пдфный Form и дописываю потом страницу, которая включает в себя эти Form-ы. Мне кажется это быстрее.


                Если куски, то это круто! Я до таких высот еще не опускался. Мне вроде как и не надо, но было бы интересно.

                  0
                  Квантом является кривая(4точки) + fill + stroke(способы обводки и заливки) + матрица. Кроме того, шрифты описываются аналогично. Т.е. всю страницу, кроме растра можно описать списком этих структур QPainterPath + QBrush/QPen + QMatrix/QTransform. Аналогично c SVG и TTF/OTF. Т.е вы оперируете этим списком безотносительно источника (двигать, удалять, добавлять, крутить), а затем этот список сериализуете либо pdf либо в svg либо еще во что.
                    0
                    А как со скоростью? Это для подчеркиваний и выделений? Может быстрее будет накладывать поверх объекта страницы второй объект с выделениями?
                      0
                      Нет не для подчеркиваний и выделений. Для всего. Практически все в пдф представлено, в виде кривых (буквы в тексте, изображения(кроме растра), контуры, короче вообще всЁ). Соответсвенно, практически все можно представить в виде 4(3) точек и способа обводки/заливки получившегося контура. Глиф в шрифте, кстати имеет аналогичную структуру. В mupdf или pdfium все работает аналогично, просто за отрисовку полученных кривых отвечает, если мне память не изменяет — skia. т.е. в качестве системы отрисовки я использую нативный кьютовый QPainter, а не skia, или что там использует Ваш рендер. Скорость +-аналогична. Зато полный контроль над рендерингом. Вывод гораздо быстрей, поскольку можно гнать сразу в опенгль текстуру.

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое