簡體   English   中英

如何正確使用Qt QML圖像提供程序

[英]How to correctly use Qt QML Image Provider

我正在開發一個跨平台應用程序,該應用程序通過C ++端的REST API接收圖像,然后通過ImageProvider將它們發送到QML,這似乎會導致內存泄漏。 內存泄漏的速度與圖像的大小和更新間隔成正比。

我嘗試禁用QML Image的緩存,但沒有改變。 我還嘗試通過在圖像更新上運行gc()來強制進行垃圾收集,但是仍然沒有運氣。

為了完全確定這不是由我的錯誤編碼等引起的。我創建了一個最小演示,它基於以下Qt示例: http : //doc.qt.io/qt-5/qquickimageprovider.html

唯一的補充是我增加了圖像大小,並實現了將紅色圖像替換為黃色圖像的方法。 一旦運行該應用程序,圖像將每秒更改顏色,並且內存將不斷增加。 圖片的尺寸為10000x10000,因此您可以清楚地看到它的增加。 即使圖像是10x10或任何其他大小,仍然會發生內存泄漏。

我設法在Android手機,Macbook以及運行Fedora的PC上復制了此問題。

如果您發現發生這種情況的任何原因,並且如果是錯誤,請告訴我,可以使用哪種解決方法將圖像發送到QML。 我需要在通過REST API接收到這些圖像后立即發送這些圖像,因此通常在30FPS左右。

任何幫助將不勝感激! 完整的解決方案如下。 Image和Pixmap提供程序都引起相同的問題。 如果要測試原始的Qt代碼,請在main.cpp中更改QQuickImageProvider :: Image QQuickImageProvider :: Pixmap。

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
#include <QThread>

#include "imageProvider.h"

class MyThread : public QThread
{
public:
    MyThread(QObject* object) : m_object(object)
    {
    }

    virtual void run()
    {
        QVariant colour = "red";

        while (isRunning())
        {
            QMetaObject::invokeMethod(
                m_object, "updateViewport", Q_ARG(QVariant, colour));

            if (colour == "red")
            {
                colour = "yellow";
            }
            else
            {
                colour = "red";
            }

            QThread::sleep(1);
        }
    }

private:
    QObject* m_object;
};

int main(int argc, char* argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.addImageProvider(QLatin1String("imageprovider"),
                            new ImageProvider(QQuickImageProvider::Image));
    QQmlComponent component(&engine, "qrc:/main.qml");
    QObject* object = component.create();
    MyThread* myThread = new MyThread(object);
    myThread->start();

    return app.exec();
}

imageProvider.h

#ifndef IMAGE_PROVIDER_H
#define IMAGE_PROVIDER_H

#include <QQuickImageProvider>
#include <QPixmap>
#include <QPainter>

class ImageProvider : public QObject, public QQuickImageProvider
{
    Q_OBJECT
public:
    explicit ImageProvider(ImageType type, Flags flags = 0);
    QPixmap requestPixmap(const QString& id,
                          QSize* size,
                          const QSize& requestedSize);
    QImage requestImage(const QString& id,
                        QSize* size,
                        const QSize& requestedSize);
};
#endif // IMAGE_PROVIDER_H

imageProvider.cpp

#include "imageProvider.h"

using namespace std;

ImageProvider::ImageProvider(ImageType type, Flags flags)
    : QQuickImageProvider(type, flags)
{
}

QPixmap ImageProvider::requestPixmap(const QString& id,
                                     QSize* size,
                                     const QSize& requestedSize)
{
    int width = 10000;
    int height = 10000;

    if (size)
    {
        *size = QSize(width, height);
    }

    QPixmap pixmap(requestedSize.width() > 0 ? requestedSize.width() : width,
                   requestedSize.height() > 0 ? requestedSize.height() :
                                                height);
    pixmap.fill(QColor(id).rgba());
    QPainter painter(&pixmap);
    QFont f = painter.font();
    f.setPixelSize(20);
    painter.setFont(f);
    painter.setPen(Qt::black);
    if (requestedSize.isValid())
        painter.scale(requestedSize.width() / width,
                      requestedSize.height() / height);
    painter.drawText(QRectF(0, 0, width, height), Qt::AlignCenter, id);

    return pixmap;
}

QImage ImageProvider::requestImage(const QString& id,
                                   QSize* size,
                                   const QSize& requestedSize)
{
    return QImage(10000, 10000, QImage::Format_ARGB32);
}

main.qml

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("MemoryLeakDemo")

    function updateViewport(colour) {
        image.source = "image://imageprovider/" + colour;
    }

    Image {
        id: image
        cache: false
    }
}

memoryLeakDemo.pro

QT += qml quick

CONFIG += c++11

SOURCES += main.cpp \
    imageProvider.cpp

RESOURCES += qml.qrc

DEFINES += QT_DEPRECATED_WARNINGS

qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

HEADERS += imageProvider.h

Qt已經確認這是一個錯誤,因此希望它將盡快得到解決:

https://bugreports.qt.io/browse/QTBUG-62600

同時,您可以嘗試應用補丁並從源代碼編譯框架:

https://codereview.qt-project.org/#/c/200715/

希望這可以幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM