如何在PyQt中使用pdf.js查看器呈现PDF?

6

我尝试在我的项目中添加pdf.js查看器文件,它可以在Chrome、Mozilla、Safari等浏览器中正常工作,但是在node-webkit和PyQt Webkit中无法加载某些页面。

我正在尝试使用iframe来加载文件,像这样:

<iframe src="/test/?file=/assets/pdf/example.pdf#page=3"> </iframe>

通常强烈建议展示您相关的代码。 - Nick Dickinson-Wilde
跨帖 https://github.com/mozilla/pdf.js/issues/4715 - async5
3个回答

9
以下是使用PyQt4/QtWebKit或PyQt5/QtWebEngine与pdf.js的最新演示脚本。要尝试这些脚本,请先下载最新稳定版本的pdf.js并将zip文件解压缩到适当的位置。(注意:如果您使用Linux,则发行版可能已经安装了pdf.js软件包,因此可以安装它)。
更新:
从Qt-5.13.0开始,还可以使用QWebEngineView中的内置Chromium PDF Viewer

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脚本:

更新:

注意: 截至2022年8月,可能需要使用pdfjs的旧版本构建(即下载页面上的“旧版浏览器”构建)才能使PyQt5正常工作。稳定版本应该可以与PyQt6一起正常工作。

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 脚本:

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_())

谢谢确认。我没有意识到除了Qt和PyQt5之外还需要安装PyQtWebEngine。使用“pip install PyQtWebEngine”已经解决了问题。 - user2514157
@dukeeloo 在我的Linux系统上,使用qt-5.15.2和pdfjs-2.11.388都能正常工作。如果你能升级到qt-5.13.x或更高版本,你也可以使用内置的Chromium PDF查看器。请参考我的更新答案。 - ekhumoro
@dukeeloo 嗯,显然存在版本兼容性问题。如果您坚持使用像conda这样过时的软件,这种情况迟早会发生。您正在使用哪个版本的 pdfjs?尝试过所有四个当前的预构建版本了吗?如果这些都不起作用,您可以尝试构建较早的版本之一。当然,也可能是由于您的qt/webengine版本中存在错误,这种情况下我没有看到任何明显的解决方案(除了放弃conda)。 - ekhumoro
@dukeeloo 最新的qt-5.12 (LTS)版本是5.12.12。您能否至少升级到这个版本?(注:官方对qt-5.12的支持将于2021年12月5日结束,因此不会再有更多的补丁发布)。 - ekhumoro
@ekhumoro 我只尝试了最新版本的pdfjs-2.10.377。pyqt 5.12.12目前还没有在conda-forge上。我知道我应该改用pip,如果还有其他问题,我会这样做。现在我可以不使用此功能,并希望conda很快就会更新。再次感谢。 - dukeeloo
显示剩余4条评论

7

我在Qt论坛上找到了这个帖子, thebeast44发布了一段Qt代码片段来回答你的问题。我将其翻译成了Python,如下所示。

你还需要解压作者原始代码中的res文件夹,我认为他只是修改了查看器...我也在这里附上了该代码。

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。我在node-webkit和qtpy中都有工作,非常感谢您。 - Kantanand US

2
从PyQt5 v5.13开始,您可以使用Chromium API加载PDF文件。根据文档https://doc.qt.io/qt-5/qtwebengine-features.html#pdf-file-viewing,此选项默认已启用。
这个最小化的例子是从简单浏览器中适配而来。
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_())

这个例子:

这个例子


根据 https://doc.qt.io/qt-5/qaxcontainer-module.html,QAxContainer 是专门针对 Windows 的。那么 Linux 用户有其他选项吗? - user2514157
很遗憾,不是的 :( - Mario Sergio Valdes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接