6

I have tried adding the pdf.js viewer files in my project and it works in browsers like Chrome, Mozilla, Safari, etc, but it's not loading some pages in node-webkit and PyQt webkit.

I am trying to load the file using an iframe, like this:

<iframe src="/test/?file=/assets/pdf/example.pdf#page=3"> </iframe>
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
Kantanand US
  • 108
  • 1
  • 1
  • 7

3 Answers3

9

Below are some more up-to-date demo scripts for using pdf.js with PyQt4/QtWebKit or PyQt5/QtWebEngine. To try these, first download the latest stable version of pdf.js and unpack the zip file into a suitable location. (NB: if you're on Linux your distro may already have a pdf.js package, so that could be installed instead).

UPDATE:

As of Qt-5.13.0, it is also possible to use the built-in Chromium PDF Viewer with QWebEngineView:

screenshot

import sys
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets

PDF = 'file://path/to/my/sample.pdf'

class Window(QtWebEngineWidgets.QWebEngineView):
    def __init__(self):
        super().__init__()
        self.settings().setAttribute(
            QtWebEngineWidgets.QWebEngineSettings.PluginsEnabled, True)
        self.settings().setAttribute(
            QtWebEngineWidgets.QWebEngineSettings.PdfViewerEnabled, True)
        self.load(QtCore.QUrl.fromUserInput(PDF))

if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.setGeometry(600, 50, 800, 600)
    window.show()
    sys.exit(app.exec_())

PyQt5/QtWebEngine pdfjs script:

UPDATE:

NB: as of Aug 2022, it may be necessary to use the legacy build of pdfjs (i.e. the build for "older browsers" on the download page) to keep things working with PyQt5. The stable build should work okay with PyQt6, though.

screenshot

import sys
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets

PDFJS = 'file:///path/to/pdfjs-1.9.426-dist/web/viewer.html'
# PDFJS = 'file:///usr/share/pdf.js/web/viewer.html'
PDF = 'file:///path/to/my/sample.pdf'

class Window(QtWebEngineWidgets.QWebEngineView):
    def __init__(self):
        super().__init__()
        self.load(QtCore.QUrl.fromUserInput('%s?file=%s' % (PDFJS, PDF)))

if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.setGeometry(600, 50, 800, 600)
    window.show()
    sys.exit(app.exec_())

PyQt4/QtWebKit pdfjs script:

import sys
from PyQt4 import QtCore, QtGui, QtWebKit

PDFJS = 'file:///path/to/pdfjs-1.9.426-dist/web/viewer.html'
# PDFJS = 'file:///usr/share/pdf.js/web/viewer.html'
PDF = 'file:///path/to/my/sample.pdf'

class Window(QtWebKit.QWebView):
    def __init__(self):
        super().__init__()
        self.load(QtCore.QUrl.fromUserInput('%s?file=%s' % (PDFJS, PDF)))

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.setGeometry(600, 50, 800, 600)
    window.show()
    sys.exit(app.exec_())
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • When I run the PyQt5/QtWebEngine script, I see "0 of 0" and "automatic zoom" in the menu bar but the display area is empty. The following error is displayed in the console: js: Uncaught (in promise) ReferenceError: globalThis is not defined. I am running the most recent anaconda packages (python 3.8, qt 5.9.7, pyqt 5.9.2) on Ubuntu 20.04. Any ideas? – user2514157 Jan 28 '21 at 02:57
  • @user2514157 I just tested the script in my answer using pdfjs-2.6.347 with qt 5.15.2 and pyqt 5.15.2 and it works fine for me on linux. Does ubuntu have a pdfjs package? If it does, you should use that, otherwise there may be version incompatibilities. – ekhumoro Jan 28 '21 at 03:08
  • Thank you for confirming. I did not realize it was necessary to install PyQtWebEngine in addition to Qt and PyQt5. Fixed with "pip install PyQtWebEngine". – user2514157 Jan 28 '21 at 03:49
  • When I try the PyQt5/QtWebEngine script I get the error message js: Uncaught SyntaxError: Unexpected token . js: Uncaught SyntaxError: Unexpected token ? The viewer controls are visible but the content remains blank. I'm using python 3.7 / windows 10 / pyqtwebengine 5.12.1 / pyqt 5.12.3. Any Ideas? – dukeeloo Nov 30 '21 at 16:42
  • @dukeeloo Works fine for me using qt-5.15.2 and pdfjs-2.11.388 on linux. You could also use the built-in chromium pdf viewer if you can upgrade to qt-5.13.x or greater. See my updated answer. – ekhumoro Nov 30 '21 at 17:16
  • Thank you for adding this. I'm using conda and am stuck with pyqt5<5.13 for now. (see https://github.com/spyder-ide/spyder/issues/12829) Independent of this I don't see why your PyQt5/QtWebEngine pdfjs script would not work in my installation. – dukeeloo Dec 01 '21 at 11:07
  • @dukeeloo Well, obviously there's a version compatibility issue. If you insist on using outdated software like conda, it's inevitable this will happen sooner or later. Which version of `pdfjs` are you using? Have tried all four of the [current prebuilds](https://mozilla.github.io/pdf.js/getting_started/#download)? If none of those work, you could [try building one of the earlier releases](https://github.com/mozilla/pdf.js). Of course, it could also be due to a bug in your version of qt/webengine, in which case I don't see any obvious solution (other than ditching conda, that is). – ekhumoro Dec 01 '21 at 17:31
  • @dukeeloo The [latest version of qt-5.12 (LTS)](https://wiki.qt.io/Qt_5.12_Release) is 5.12.12. Are you at least able to upgrade to that? (NB: official support for qt-5.12 ends on 5th Dec 2021, so there won't be any more patch releases). – ekhumoro Dec 01 '21 at 17:54
  • @ekhumoro I only tried with the latest version pdfjs-2.10.377. pyqt 5.12.12 is not on conda-forge yet. I know I should change to pip and I will if there is one more issue. For now I can live without this feature and hope conda will be updated very soon. Thanks again. – dukeeloo Dec 01 '21 at 18:26
7

I've found this thread over at the Qt Forums, where thebeast44 posted a snippet of Qt code answering your question. My translation to python is below.

You'll also need to unpack the res folder from the author's original code, I think he just modified the viewer... I've also attached said code here.

from PyQt4 import QtCore
from PyQt4 import QtGui
from PyQt4 import QtNetwork
from PyQt4 import QtWebKit


class PDFViewer(QtWebKit.QWebView):
    pdf_viewer_page = 'res/pdf-viewer.html'

    def __init__(self, parent=None):
        super().__init__(parent)
        self.settings = QtWebKit.QWebSettings.globalSettings()
        self.settings.setAttribute(QtWebKit.QWebSettings.LocalContentCanAccessFileUrls, True )
        self.settings.setAttribute(QtWebKit.QWebSettings.LocalContentCanAccessRemoteUrls, True )
        self.settings.setAttribute(QtWebKit.QWebSettings.DeveloperExtrasEnabled, True )
        nam = QtNetwork.QNetworkAccessManager()
        page = QtWebKit.QWebPage(self)
        page.setNetworkAccessManager(nam)
        self.setPage(page)
        self.loadFinished.connect(self.onLoadFinish)
        self.setUrl(QtCore.QUrl(self.pdf_viewer_page))

    def onLoadFinish(self, success):
        if success:
            self.page().mainFrame().evaluateJavaScript("init();")


if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)
    viewer = PDFViewer(parent=None)
    viewer.show()
    sys.exit(app.exec_())
fstafforini
  • 143
  • 6
2

From PyQt5 v5.13 you can load PDF files with the chromium API. According to the documentation https://doc.qt.io/qt-5/qtwebengine-features.html#pdf-file-viewing this option is by default enabled.

This minimal example is adapted from Simple Browser

import sys
from pathlib import Path

from PyQt5 import QAxContainer
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QLineEdit, QApplication


class Main(QWidget):
    def __init__(self, parent=None):
        super(Main, self).__init__(parent)
        self.main_layout = QVBoxLayout(self)

        self.qlineedit = QLineEdit()
        self.qlineedit.returnPressed.connect(self.go_action)
        self.main_layout.addWidget(self.qlineedit)
        self.read_btn = QPushButton('Test')
        self.read_btn.clicked.connect(self.go_action)
        self.main_layout.addWidget(self.read_btn)

        self.WebBrowser = QAxContainer.QAxWidget(self)
        self.WebBrowser.setFocusPolicy(Qt.StrongFocus)
        self.WebBrowser.setControl("{8856F961-340A-11D0-A96B-00C04FD705A2}")
        self.main_layout.addWidget(self.WebBrowser)

    def go_action(self):
        # convert system path to web path
        f = Path(self.qlineedit.text()).as_uri()
        # load object 
        self.WebBrowser.dynamicCall('Navigate(const QString&)', f)


if __name__ == "__main__":
    a = QApplication(sys.argv)
    w = Main()
    w.show()
    sys.exit(a.exec_())

This example:

This example

eyllanesc
  • 235,170
  • 19
  • 170
  • 241