Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Multiple same-source Images are exhausting RAM
Forum Updated to NodeBB v4.3 + New Features

Multiple same-source Images are exhausting RAM

Scheduled Pinned Locked Moved Solved QML and Qt Quick
6 Posts 2 Posters 882 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    SafaAlfulaij
    wrote on last edited by SafaAlfulaij
    #1

    Hello.
    I have a simple QML file containing an Image. This file is resued several times (20-30) in my application (both directly and in a Repeater). The idea of the file is to crop the image using the different parts of it. Editing the image is not possible.
    The problem is that the applications starts to use more and more RAM for the exact same Image (from 100mb -> 1GB). Is there a way to solve this?

    Samples:
    MyImage.qml:

    import QtQuick 2.12
    
    Item {
        id: root
    
        property int nowX: 0
        property int nowY: 0
        property int imageSource: 0
    
        implicitWidth: 50
        implicitHeight: 50
    
        Item {
            clip: true
    
            Image {
                x: root.nowX
                y: root.nowY
    
                source: root.imageSource
                fillMode: Image.PreserveAspectFit
            }
        }
    }
    

    Main file:

    import QtQuick 2.12
    
    Flow {
        Repeater {
               model: [[0,0], [100,100], [210, 240]] // Sample values
    
            MyImage {
                imageSource: "somePathToA1024x1024Image"
                nowX: modelData[0]
                nowY: modelData[1]
            }
        }
    }
    
    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      Do you really need such a big image ?
      What about using an image cache through for example a custom image provider.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      S 1 Reply Last reply
      1
      • SGaistS SGaist

        Hi,

        Do you really need such a big image ?
        What about using an image cache through for example a custom image provider.

        S Offline
        S Offline
        SafaAlfulaij
        wrote on last edited by SafaAlfulaij
        #3

        @SGaist

        The image actually is from the user (this is a tool and that MyImage.qml is the editor).
        It's an image from gaming textures (216x216, 512x512, 1024, 2048), so I can't change it.
        I tried QQuickImageProvider but I misunderstood it's idea.

        PyQt5:

        class CachedImageProvider(QQuickImageProvider):
            def __init__(self):
                QQuickImageProvider.__init__(self, QQuickImageProvider.Image)
                self._cache = {}
        
            def requestImage(self, filePath, requestedSize): # filePath = id
                fileUrl = QUrl(filePath).toLocalFile() # remove file://
        
                if not fileUrl:
                    return QImage(1, 1, QImage.Format_ARGB32), QSize(1, 1)
        
                if fileUrl in self._cache:
                    return self._cache[fileUrl], self._cache[fileUrl].size()
        
                image = None
                with open(fileUrl, 'rb') as handle:
                    image = QImage.fromData(handle.read())
        
                if not image:
                    return QImage(1, 1, QImage.Format_ARGB32), QSize(1, 1)
        
                self._cache[fileUrl] = image
                return image, image.size()
        
        if __name__ == "__main__":
            QGuiApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
            app = QGuiApplication(sys.argv)
        
        
            qmlRegisterType(CommonFontFile, 'Backend', 1, 0, 'BackendFile')
        
            engine = QQmlApplicationEngine()
            engine.addImageProvider('CachedImageProvider', CachedImageProvider())
        
            engine.load('qrc:/qml/main.qml')
            if not engine.rootObjects():
                sys.exit(-1)
        
            res = app.exec_()
            # Deleting the view before it goes out of scope is required to make sure all child QML instances
            # are destroyed in the correct order.
            del engine
            sys.exit(res)
        
        

        It works correctly (with the proper scheme and id from QML side), and shows correct. But RAM usage still increase with each instance. Also, the provider is called once, as the documentation says. Disabling cache does nothing, as the provider's cache isn't saved.
        I am missing something for sure, and sorry about that.
        Thanks for your time! :)

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          I was thinking about QPixmapCache.

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          S 1 Reply Last reply
          1
          • SGaistS SGaist

            I was thinking about QPixmapCache.

            S Offline
            S Offline
            SafaAlfulaij
            wrote on last edited by
            #5

            @SGaist

            So something like this? (Still, same)

            class CachedImageProvider(QQuickImageProvider):
                def __init__(self):
                    QQuickImageProvider.__init__(self, QQuickImageProvider.Pixmap)
            
                def requestPixmap(self, filePath, requestedSize): # filePath = id
                    fileUrl = QUrl(filePath).toLocalFile()
            
                    if not fileUrl:
                        return QPixmap(1, 1), QSize(1, 1)
            
                    pm = QPixmap(1, 1)
                    if not QPixmapCache.find(fileUrl):
                        pm.load(fileUrl)
                        QPixmapCache.insert(fileUrl, pm)
            
                    return pm, pm.size()
            
            1 Reply Last reply
            0
            • SGaistS Offline
              SGaistS Offline
              SGaist
              Lifetime Qt Champion
              wrote on last edited by
              #6

              It's rather:

                  pm = QPixmapCache.find(fileUrl)
                  if pm is None:
                      pm = QPixmap(fileUrl)
                      QPixmapCache.insert(fileUrl, pm)
              
                  return pm, pm.size()
              

              As it is, your code sample fills the QPixmapCache or returns a 1, 1 QPixmap, however, it does re-use the content of the cache.

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              1 Reply Last reply
              2

              • Login

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved