…Или как мы писали пилот приложения для ОС 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, поэтому собираюсь переписать все это дело на другой библиотеке, это что-то невероятно мощное на первый взгляд, надеюсь, что заявленная функциональность действительности соответствует.

Если кто пробовал или знает решение более подходящее, буду максимально признательна за совет.

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


  1. al_sh
    19.02.2019 14:25

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


    1. nastika Автор
      19.02.2019 15:08

      в Sailfish Qt 5.6, QPdf для более поздних версий, если я правильно помню)


      1. al_sh
        19.02.2019 15:25

        да, но ничего не мешает собрать и для 5.6 blog.qt.io/blog/2017/01/30/new-qtpdf-qtlabs-module.


  1. apro
    19.02.2019 14:29

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


    1. nastika Автор
      19.02.2019 15:09

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


      1. al_sh
        19.02.2019 15:26

        вполне себе пишет


    1. Gorthauer87
      19.02.2019 20:15

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


  1. ranissafiullin9
    19.02.2019 20:07

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


  1. AndrewSu
    20.02.2019 09:20

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


  1. SokoloffA
    20.02.2019 13:57
    +1

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

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


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


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


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


    1. al_sh
      20.02.2019 14:15

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


  1. SokoloffA
    20.02.2019 15:34

    Я пдф, через pdfium в набор QPainterPath складываю, а затем отрисовываю по мере необходимости.

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


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


    1. al_sh
      20.02.2019 16:34

      Квантом является кривая(4точки) + fill + stroke(способы обводки и заливки) + матрица. Кроме того, шрифты описываются аналогично. Т.е. всю страницу, кроме растра можно описать списком этих структур QPainterPath + QBrush/QPen + QMatrix/QTransform. Аналогично c SVG и TTF/OTF. Т.е вы оперируете этим списком безотносительно источника (двигать, удалять, добавлять, крутить), а затем этот список сериализуете либо pdf либо в svg либо еще во что.


      1. SokoloffA
        20.02.2019 17:12

        А как со скоростью? Это для подчеркиваний и выделений? Может быстрее будет накладывать поверх объекта страницы второй объект с выделениями?


        1. al_sh
          20.02.2019 17:29

          Нет не для подчеркиваний и выделений. Для всего. Практически все в пдф представлено, в виде кривых (буквы в тексте, изображения(кроме растра), контуры, короче вообще всЁ). Соответсвенно, практически все можно представить в виде 4(3) точек и способа обводки/заливки получившегося контура. Глиф в шрифте, кстати имеет аналогичную структуру. В mupdf или pdfium все работает аналогично, просто за отрисовку полученных кривых отвечает, если мне память не изменяет — skia. т.е. в качестве системы отрисовки я использую нативный кьютовый QPainter, а не skia, или что там использует Ваш рендер. Скорость +-аналогична. Зато полный контроль над рендерингом. Вывод гораздо быстрей, поскольку можно гнать сразу в опенгль текстуру.