QML Camera Application
This Qt Quick based application shows how to use the API to capture a still image or video.
This example demonstrates how to access camera functions via QML. It shows how to change settings and capture images or video.
Running the Example
To run the example from Qt Creator, open the Welcome mode and select the example from Examples. For more information, visit Building and Running an Example.
Application structure
Most of the QML code in this example supports the user interface. Custom types that support the requirements have been implemented using existing Qt Quick controls.
Using screen orientation to select layout
In declarative-camera.qml
we handle detecting the orientation we're in and select the appropriate layout while also catering for the limitations of small screen mobile devices like so:
Rectangle { id : cameraUI width: 800 height: 480 color: "black" state: "PhotoCapture" property string platformScreen: "" property int buttonsPanelLandscapeWidth: 328 property int buttonsPanelPortraitHeight: 180 onWidthChanged: { setState() } function setState() { if (Qt.platform.os === "android" || Qt.platform.os === "ios") { if (Screen.desktopAvailableWidth < Screen.desktopAvailableHeight) { stillControls.state = "MobilePortrait"; } else { stillControls.state = "MobileLandscape"; } } else { stillControls.state = "Other"; } console.log("State: " + stillControls.state); stillControls.buttonsWidth = (stillControls.state === "MobilePortrait") ? Screen.desktopAvailableWidth/3.4 : 144 }
Here is the portrait layout:
You can see the state
property is initially set as PhotoCapture
.
Then the states
themselves are defined like so:
states: [ State { name: "PhotoCapture" StateChangeScript { script: { camera.start() } } }, State { name: "PhotoPreview" }, State { name: "VideoCapture" StateChangeScript { script: { camera.start() } } }, State { name: "VideoPreview" StateChangeScript { script: { camera.stop() } } } ]
Controls for capturing
Controls for capturing are implemented in PhotoCaptureControls.qml
and VideoCaptureControls.qml. They each are based on a FocusScope that defines common buttons dimensions and margins that are used by the control buttons and then declares the buttons.
This generates a column on the right hand side of the screen which includes, listed top to bottom, the following controls:
- A
Capture
orRecord
button, which initiates capturing. - A
capture properties
button that displays the icon of the current white balance mode selected and when pressed uses a pop-up to displays the following option's icons:- Flash mode (if available)
- White balance modes
- Exposure compensation
- A
View
button, once something has been captured. - A button which displays the currently selected capture device and when pressed provides a list of available devices to switch to, using a pop-up.
- A
Switch To
button that displays the alternate capture mode (video or photo) depending on the current active selection and switches the mode when pressed. - A
Quit
button, that exits the application.
Image capturing
The button that triggers this is defined in CameraButton.qml: but its interaction with the camera is in the controls types, lets look at PhotoCaptureControls:
CameraButton { text: "Capture" implicitWidth: buttonsWidth visible: captureSession.imageCapture.readyForCapture onClicked: captureSession.imageCapture.captureToFile("") }
Zoom control
Implemented in ZoomControl.qml
the ZoomControl type is based on an Item and creates a bar that represents the zoom level, which can also be dragged. It uses an exponential calculation method to determine the zoom factor given the position of the grove
.
The bar is only visible if the initialZoom is greater than 1. This means the currently active camera has a zoom function.
Item { id : zoomControl property real currentZoom : 1 property real maximumZoom : 1 signal zoomTo(real target) visible: zoomControl.maximumZoom > 1 MouseArea { id : mouseArea anchors.fill: parent property real initialZoom : 0 property real initialPos : 0 onPressed: { initialPos = mouseY initialZoom = zoomControl.currentZoom } onPositionChanged: { if (pressed) { var target = initialZoom * Math.pow(5, (initialPos-mouseY)/zoomControl.height); target = Math.max(1, Math.min(target, zoomControl.maximumZoom)) zoomControl.zoomTo(target) } } } Item { id : bar x : 16 y : parent.height/4 width : 24 height : parent.height/2 Rectangle { anchors.fill: parent smooth: true radius: 8 border.color: "white" border.width: 2 color: "black" opacity: 0.3 } Rectangle { id: groove x : 0 y : parent.height * (1.0 - (zoomControl.currentZoom-1.0) / (zoomControl.maximumZoom-1.0)) width: parent.width height: parent.height - y smooth: true radius: 8 color: "white" opacity: 0.5 } Text { id: zoomText anchors { left: bar.right; leftMargin: 16 } y: Math.min(parent.height - height, Math.max(0, groove.y - height / 2)) text: "x" + Math.round(zoomControl.currentZoom * 100) / 100 font.bold: true color: "white" style: Text.Raised; styleColor: "black" opacity: 0.85 font.pixelSize: 18
In PhotoCaptureControls.qml and VideoCaptureControls.qml the signal zoomTo
will set the selected camera's zoomFactor property to the calculated target
value, as well as updating the ZoomControl bar.
ZoomControl { x : 0 y : captureControls.state === "MobilePortrait" ? -buttonPaneShadow.height : 0 width : 100 height: parent.height currentZoom: captureSession.camera.zoomFactor maximumZoom: captureSession.camera.maximumZoomFactor onZoomTo: captureSession.camera.zoomFactor = target } states: [ State { name: "MobilePortrait" PropertyChanges { target: buttonPaneShadow width: parent.width height: buttonsPanelPortraitHeight } PropertyChanges { target: buttonsColumn height: captureControls.buttonsPanelPortraitHeight / 2 - buttonsmargin } PropertyChanges { target: bottomColumn height: captureControls.buttonsPanelPortraitHeight / 2 - buttonsmargin } AnchorChanges { target: buttonPaneShadow anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right } AnchorChanges { target: buttonsColumn anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top } AnchorChanges { target: bottomColumn; anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right } }, State { name: "MobileLandscape" PropertyChanges { target: buttonPaneShadow width: buttonsPanelWidth height: parent.height } PropertyChanges { target: buttonsColumn height: parent.height width: buttonPaneShadow.width / 2 } PropertyChanges { target: bottomColumn height: parent.height width: buttonPaneShadow.width / 2 } AnchorChanges { target: buttonPaneShadow anchors.top: parent.top anchors.right: parent.right } AnchorChanges { target: buttonsColumn; anchors.top: parent.top anchors.bottom: parent.bottom anchors.left: parent.left; } AnchorChanges { target: bottomColumn; anchors.top: parent.top; anchors.bottom: parent.bottom; anchors.right: parent.right; } }, State { name: "Other" PropertyChanges { target: buttonPaneShadow; width: bottomColumn.width + 16; height: parent.height; } AnchorChanges { target: buttonPaneShadow; anchors.top: parent.top; anchors.right: parent.right; } AnchorChanges { target: buttonsColumn; anchors.top: parent.top anchors.right: parent.right } AnchorChanges { target: bottomColumn; anchors.bottom: parent.bottom; anchors.right: parent.right; } } ] }
Flash and torch control
Defined in FlashControl.qml
this enables flash mode selection and torch functionality to be toggled via a Switch. As with the zoom control, the switches are only visible on top of the preview window if the active device supports these functions.
Here we check if the functions are supported:
Here we implement the flashModeControl
switch, which also directly controls the Camera device.
Torch control is implemented in a similar way.
© 2024 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.