Search code examples
qtqmlpyside6

Transport QML Image via Bridge


I have at the moment a simple PySide6 app which uses qml for image capturing. I want to transport the image to our app but cannot figure out how. I am not sure, if saving QML image is an attempt in the right direction.

My PySide App

import sys
from pathlib import Path
from PySide6.QtCore import QObject, Slot
from PySide6.QtGui import QGuiApplication, QImage
from PySide6.QtQml import QQmlApplicationEngine, QmlElement


QML_IMPORT_NAME = "io.qt.textproperties"
QML_IMPORT_MAJOR_VERSION = 1


@QmlElement
class Bridge(QObject):
    @Slot(QImage)
    def capture(self, preview):
        # Do something with the preview
        print(type(preview))


if __name__ == "__main__":
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()

    # Get the path of the current directory, and then add the name
    # of the QML file, to load it.
    qml_file = Path(__file__).parent / "simpleCam.qml"
    engine.load(qml_file)

    if not engine.rootObjects():
        sys.exit(-1)

    sys.exit(app.exec())

MY QML File

import QtQuick
import QtQuick.Controls
import QtMultimedia

import io.qt.textproperties


ApplicationWindow {
    id: mainFrame
    width: 640
    height: 480
    visible: true
    title: qsTr("Cam Test")
    
    Bridge {
        id: bridge
    }

    Rectangle {
        width: 640
        height: 400
       
        MediaDevices {
            id: mediaDevices
        }

        CaptureSession {
            imageCapture: ImageCapture {
                id: capture
            }
            camera: Camera {
                id: camera                
            }
            videoOutput: output
        }

        VideoOutput {
            id: output
            anchors.fill: parent
        }

        Button {
            id: startCamButton
            text: "Start Cam"
            anchors.top: output.bottom
            anchors.left: output.left
            onClicked: {
                camera.start()
                camImage.opacity = 0
            }
        }

        Button {
            id: takePicButton
            text: "take pic"
            anchors.top: output.bottom
            anchors.left: startCamButton.right
            onClicked: {
                capture.capture()
                camImage.opacity = 1
            }
        }

        Image {
            id: camImage
            anchors.fill: parent
            source: capture.preview
        }
    }
}

The Result

enter image description here

What is missing?

In the Button with id: takePicButton I want to transport the image to the PySide6 Bridge. If I add to theonClicked Signal bridge.capture(capture.preview) I got the Error:

TypeError: Passing incompatible arguments to C++ functions from JavaScript is not allowed.`

How can I solve this problem?


Solution

  • You should use the imageCaptured signal.

    Change:

    imageCapture: ImageCapture {
        id: capture
    }
    

    To:

    imageCapture: ImageCapture {
        id: capture
        onImageCaptured: function(req_id, preview){bridge.capture(req_id, preview)}
    }
    

    And change in main.py:

    @Slot(QImage)
    def capture(self, preview):
        # Do something with the preview
        print(type(preview))
    

    To:

    @Slot(int, QImage)
    def capture(self,req_id, preview):
        print(req_id)
        print(type(preview))
    

    Working example here.
    You might want to look at this answer for other use cases.