QWebEngineView无法使用setHtml加载大型SVG/HTML

问题描述 投票:0回答:1

我尝试了两种不同的方法在 PyQt 中加载和显示 SVG 文件:

import sys
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QUrl

app = QApplication(sys.argv)
webView = QWebEngineView()

# Variant 1: Reasonably fast
webView.load(QUrl('file:///Test.svg'))

# Variant 2: Slow for small files, not working for big ones
webView.setHtml('<svg>........')

webView.show()
sys.exit(app.exec_())

第一种方法工作正常,但需要一个文件作为输入。不过,我想动态生成 SVG,所以这并不是一个真正的选择。有谁知道为什么第二种方法对于更复杂的矢量图像来说如此缓慢或完全失败?

python qt svg pyqt5 qtwebengine
1个回答
2
投票

更新

解决此问题的方法是使用自定义 url 方案处理程序,它无需通过数据 url 传入文件内容。

这是一个基本演示,展示了如何实现这一点:

from PyQt5.QtCore import (
    QUrl, QByteArray, QBuffer, QIODevice,
)
from PyQt5.QtWidgets import (
    QApplication, QWidget, QPushButton, QCheckBox, QGridLayout,
)
from PyQt5.QtWebEngineCore import (
    QWebEngineUrlScheme, QWebEngineUrlSchemeHandler, QWebEngineUrlRequestJob,
    )
from PyQt5.QtWebEngineWidgets import QWebEngineView


HTML_DATA = {}
URL_SCHEME = 'local'
TEST_FILE = 'test.data'


class UrlSchemeHandler(QWebEngineUrlSchemeHandler):
    def requestStarted(self, job):
        href = job.requestUrl().path()
        if (data := HTML_DATA.get(href)) is not None:
            if not isinstance(data, bytes):
                data = str(data).encode()
            mime = QByteArray(b'text/html')
            buffer = QBuffer(job)
            buffer.setData(data)
            buffer.open(QIODevice.OpenModeFlag.ReadOnly)
            job.reply(mime, buffer)
        else:
            print(f'ERROR: request job failed: {href!r}')
            job.fail(QWebEngineUrlRequestJob.Error.UrlNotFound)


class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.button = QPushButton('Load Source')
        self.button.clicked.connect(self.handleButtton)
        self.option = QCheckBox('Use url scheme handler')
        self.view = QWebEngineView()
        self.view.page().profile().installUrlSchemeHandler(
            bytes(URL_SCHEME, 'ascii'), UrlSchemeHandler(self))
        self.view.loadFinished.connect(self.handleLoaded)
        layout = QGridLayout(self)
        layout.addWidget(self.view, 0, 0, 1, 2)
        layout.addWidget(self.button, 1, 0)
        layout.addWidget(self.option, 1, 1)

    def handleButtton(self):
        if self.option.isChecked():
            url = QUrl(TEST_FILE)
            url.setScheme(URL_SCHEME)
            self.view.setUrl(url)
        else:
            self.view.setHtml(HTML_DATA[TEST_FILE])

    def handleLoaded(self, ok):
        if not ok:
            self.view.setHtml('<h3>414: URI Too Long</h3>')


if __name__ == '__main__':

    try:
        HTML_DATA[TEST_FILE] = open('large.svg').read()
    except OSError:
        HTML_DATA[TEST_FILE] = (html := f"""
            <html><head></head><body>
            <h3>Test Page ({{}} MB)</h3>{'''<p>
            Lorem ipsum dolor sit amet, consectetur adipiscing
            elit, sed do eiusmod tempor incididunt ut labore et
            dolore magna aliqua. Ut enim ad minim veniam, quis
            nostrud exercitation ullamco laboris nisi ut aliquip
            ex ea commodo consequat. Duis aute irure dolor in
            reprehenderit in voluptate velit esse cillum dolore
            eu fugiat nulla pariatur. Excepteur sint occaecat
            cupidatat non proident, sunt in culpa qui officia
            deserunt mollit anim id est laborum.
            </p>''' * 4000}</body></html>"""
            ).format(round(len(html) / 1e6, 1))

    scheme = QWebEngineUrlScheme(bytes(URL_SCHEME, 'ascii'))
    scheme.setFlags(QWebEngineUrlScheme.Flag.SecureScheme |
                    QWebEngineUrlScheme.Flag.LocalScheme |
                    QWebEngineUrlScheme.Flag.LocalAccessAllowed)
    QWebEngineUrlScheme.registerScheme(scheme)

    app = QApplication(['Test'])
    window = Window()
    window.setGeometry(600, 50, 800, 600)
    window.show()
    app.exec()

setHtml
函数无法加载任何大小大于2MB的内容(不仅仅是svg)。这是因为 Chromium 使用
data:
方案 url 来加载内容(这显然将大小限制为 url 的最大长度)。所以看来唯一的选择是从本地文件加载 svg。

© www.soinside.com 2019 - 2024. All rights reserved.