如何在QWebView 中显示动态创建的图像?

How to display dynamically created images in QWebView?

我正在使用 QtWebKit 显示动态创建的 HTML 内容,我需要显示从数据库中检索到的图像。例如,如果我需要显示资源中的图像,我将此行添加到我在 QWebView::setHtml:

中使用的内容
<img src="qrc:/images/image.jpg"/>

效果很好,WebView 会自动找到资源并显示它。现在我需要用我从数据库中检索到的内容替换此图像,并且该图像在文件系统中没有文件。怎么做?

我可以管理动态添加内容的 qrc 命名空间吗?是否可以添加我自己的 QRC 处理程序来接收和服务来自 WebView 的请求?如果不是 QRC,是否有任何其他协议可用于为 WebView 中的图像提供内容?

我可以完全控制使用 setHtml 方法添加到 WebView 的内容。

更新: 我也想为 QWebEngineView 解决同样的问题。

QtWebkit

对于 QtWebkit,您必须使用 QNetworkAccessManager 拦截请求并重新发送自定义 QNetworkReply。

#include <QtWebKitWidgets>

class CustomReply : public QNetworkReply{
public:
    explicit CustomReply(const QByteArray & content, const QByteArray & contentType, const QUrl & url):
        QNetworkReply(), m_content(content){
        offset = 0;
        setUrl(url);
        open(ReadOnly | Unbuffered);
        setHeader(QNetworkRequest::ContentTypeHeader, QVariant(contentType));
        setHeader(QNetworkRequest::ContentLengthHeader, QVariant(m_content.size()));
        QTimer::singleShot(0, this, &CustomReply::dispatch);
    }
    bool isSequential() const{
        return true;
    }
    qint64 bytesAvailable() const{
        return m_content.size() - offset + QIODevice::bytesAvailable();
    }
public slots:
    void abort(){
    }
protected:
    qint64 readData(char *data, qint64 maxSize){
        if (offset < m_content.size()) {
            qint64 number = qMin(maxSize, m_content.size() - offset);
            ::memcpy(data, m_content.constData() + offset, number);
            offset += number;
            return number;
        } else
            return -1;
    }
private:
    void dispatch(){
        emit readyRead();
        emit finished();
    }
    QByteArray m_content;
    qint64 offset;
};

class NetworkAccessManager: public QNetworkAccessManager{
public:
    using QNetworkAccessManager::QNetworkAccessManager;
protected:
    QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData){
        qDebug() << request.url();
        if (request.url() == QUrl("qrc:/images/image.jpg")){

            QImage image(150, 150, QImage::Format_RGB32);
            image.fill(QColor("salmon"));

            QByteArray ba;
            QBuffer buffer(&ba);
            buffer.open(QIODevice::WriteOnly);
            image.save(&buffer, "JPEG");

            return new CustomReply(ba, "image/jpeg", request.url());
        }
        return QNetworkAccessManager::createRequest(op, request, outgoingData);
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QWebView view;
    view.resize(640, 480);
    view.show();

    view.page()->setNetworkAccessManager(new NetworkAccessManager);

    QString html = R"(<img src="qrc:/images/image.jpg">)";
    view.setHtml(html);
    return a.exec();
}

QtWebEngine

在 QtWebEngine 中,您必须实现 QWebEngineUrlSchemeHandler,但不能使用 qrc、http 或 https 模式:

#include <QtWebEngineWidgets>

#define SCHEMENAME "so"

class Handler : public QWebEngineUrlSchemeHandler{
public:
    void requestStarted(QWebEngineUrlRequestJob *job){
        if(job->requestUrl() == QUrl("so:/images/image.jpg")){
            QImage image(150, 150, QImage::Format_RGB32);
            image.fill(QColor("salmon"));

            QBuffer *buffer = new QBuffer;
            buffer->open(QIODevice::WriteOnly);
            image.save(buffer, "JPEG");
            buffer->seek(0);
            buffer->close();

            job->reply("image/jpeg", buffer);
        }
    }
    static void registerUrlScheme(){
        QWebEngineUrlScheme webUiScheme(SCHEMENAME);
        webUiScheme.setFlags(QWebEngineUrlScheme::SecureScheme |
                             QWebEngineUrlScheme::LocalScheme |
                             QWebEngineUrlScheme::LocalAccessAllowed);
        QWebEngineUrlScheme::registerScheme(webUiScheme);
    }

};


int main(int argc, char *argv[])
{
    Handler::registerUrlScheme();

    QApplication a(argc, argv);
    QWebEngineView view;

    Handler handler;
    view.page()->profile()->installUrlSchemeHandler(SCHEMENAME, &handler);
    view.resize(640, 480);
    view.show();

    QString html = R"(<img src="so:/images/image.jpg">)";
    view.setHtml(html);

    return a.exec();
}