2

I would like to view a PDF file in a WebView created in my QML code. I am importing QtWebView 1.1 and setting the url property to the path of the PDF file but I am getting this error:

[13044:12820:0314/144814.854:ERROR:in_progress_cache_impl.cc(192)] Cache is not initialized, cannot RetrieveEntry. [13044:12820:0314/144814.854:ERROR:in_progress_cache_impl.cc(176)] Cache is not initialized, cannot AddOrReplaceEntry. [13044:12820:0314/144814.854:ERROR:in_progress_cache_impl.cc(192)] Cache is not initialized, cannot RetrieveEntry.

When I use the same code to view an image it works. This question: Display PDF file with QWebView is close to what I want but QML does not seem to give me access to the settings method the way that C++ does (WebView docs). Is there some other way to do this?

Chris
  • 1,978
  • 3
  • 23
  • 35

2 Answers2

4

It seems that you are confusing elements, QWebView belongs to QtWebkit (uses Webkit) that no longer exists in Qt and that was replaced by Qt WebEngine (uses chromium). And another thing is WebView of Qt WebView that uses the native APIs (for example Android does not support Qt WebEngine but if WebView).

Qt WebEngine and Qt WebView does not support PDF visualization (Qt WenEngine will support it very soon) natively so a solution is to use some js library that does it as PDF.js so that is the alternative that I propose in base to an old answer.

*.pro

QT += quick webview
CONFIG += c++11
SOURCES += main.cpp
RESOURCES += qml.qrc

COPY_CONFIG = 3rdParty example.pdf
copy_cmd.input = COPY_CONFIG
copy_cmd.output = ${QMAKE_FILE_IN_BASE}${QMAKE_FILE_EXT}
copy_cmd.commands = $$QMAKE_COPY_DIR ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
copy_cmd.CONFIG += no_link_no_clean
copy_cmd.variable_out = PRE_TARGETDEPS
QMAKE_EXTRA_COMPILERS += copy_cmd

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QtWebView>

class PDFJS: public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString version READ version WRITE setVersion NOTIFY versionChanged)
    QString m_version;
public:
    QString version() const{
        return m_version;
    }
    void setVersion(QString version){
        if (m_version == version)
            return;
        m_version = version;
        Q_EMIT versionChanged(m_version);
    }
    Q_SIGNAL  void versionChanged(QString version);
    Q_INVOKABLE QUrl getUrl(const QUrl & path){
        QString pdfjs_path = QDir::current().filePath(QString("3rdParty/pdfjs-%1-dist/web/viewer.html").arg(m_version));
        QUrl pdf_url = QUrl::fromLocalFile(pdfjs_path);
        QUrlQuery query;
        query.addQueryItem("file", path.toString());
        pdf_url.setQuery(query);
        return pdf_url;
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);
    QtWebView::initialize();
    QQmlApplicationEngine engine;
    PDFJS pdfjs;
    engine.rootContext()->setContextProperty("applicationDirPath", QGuiApplication::applicationDirPath());
    engine.rootContext()->setContextProperty("PDFJS", &pdfjs);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;
    return app.exec();
}
#include "main.moc"

main.qml

import QtQuick 2.9
import QtQuick.Window 2.2
import QtWebView 1.1

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("PDFJS Example")
    WebView{
        id: webview
        anchors.fill: parent
    }
    Component.onCompleted:{
        PDFJS.version = "2.1.266"
        webview.url = PDFJS.getUrl("file://" + applicationDirPath + "/example.pdf")
    }
}

enter image description here

You can find the complete project here

Update: only QML

.
|-- 3rdParty
|   `-- pdfjs-2.1.266-dist
|-- example.pdf
`-- main.qml

main.qml

import QtQuick 2.9
import QtQuick.Window 2.2
import QtWebView 1.1

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("PDFJS Example")
    WebView{
        id: webview
        anchors.fill: parent
    }
    Component.onCompleted:{
        var pdfjs_path = Qt.resolvedUrl("3rdParty/pdfjs-2.1.266-dist/web/viewer.html")
        var path = Qt.resolvedUrl("example.pdf");
        var url = pdfjs_path + "?file=%1".arg(path)
        console.log(url)
        webview.url = url
    }
}

This part of the project you find here

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thanks, that looks like a good option but I'm restricted to QML-only solutions because I am using the ESRI AppStudio tool. Is it possible to do this without the code in main.cpp? – Chris Mar 14 '19 at 20:58
  • @Chris I think so, tell me what you get when running `console.log(Qt.resolvedUrl("."))` – eyllanesc Mar 14 '19 at 21:02
  • I get qml: file:///var/mobile/Containers/Data/Application/F343D1DB-5FBC-488C-919A-6A6893944420/Documents/ArcGIS/AppStudio/Apps/db991bee5af049bfbab26b27fde18eb2/ when I run on iOS – Chris Mar 14 '19 at 21:22
  • @Chris Try my update, I just tried it with qmlscene, but the idea is to build the url. – eyllanesc Mar 14 '19 at 21:24
  • When I put your sample into my app I got the following error: "js: Uncaught ReferenceError: require is not defined." Do I need require.js to make it work? – Chris Mar 15 '19 at 17:01
  • @Chris Not really, try it on a PC first, analyze the network traffic and just try it on IOS, I think IOS restricts a certain type of traffic (it's just a hypothesis since I'm not an expert) – eyllanesc Mar 15 '19 at 17:04
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/190105/discussion-between-chris-and-eyllanesc). – Chris Mar 15 '19 at 17:12
1

Another option to this problem is to look into the Poppler Library. This library can be used to convert a page in a PDF to an image. Take a look into the Poppler::Page object's renderToImage. The image can then be displayed on a QQuickPaintedItem. Hope this helps someone.

piper2200s
  • 151
  • 7