# 捕获图像
Camera
元素的主要功能之一是可以用来拍照。 下面将在一个简单的定格动画应用程序中使用它。 通过构建应用程序,将学习如何显示取景器、在相机之间切换、拍摄照片以及跟踪拍摄的照片。
用户界面如下所示。 它由三个主要部分组成:在背景中,可以找到取景器;右侧,是一列按钮;底部,是拍摄的图像列表。 想法是拍摄一系列照片,然后单击Play Sequence
(播放序列)按钮播放图像,创建一个简单的定格动画电影。
# 取景器
相机的取景器部分使用VideoOutput
元素作为CaptureSession
的视频输出通道。 CaptureSession
依次使用Camera
组件来配置设备,这将显示来自摄像机的实时视频流。
CaptureSession {
id: captureSession
videoOutput: output
camera: Camera {}
imageCapture: ImageCapture {
onImageSaved: function (id, path) {
imagePaths.append({"path": path})
listView.positionViewAtEnd()
}
}
}
VideoOutput {
id: output
anchors.fill: parent
}
提示
可以通过使用专用的Camera
属性(例如exposureMode
、whiteBalanceMode
或zoomFactor
)对相机行为进行更多控制。
# 捕获的图像列表
照片列表是一个水平的ListView
,它显示来自名为imagePaths
的ListModel
的图像。 在背景中,使用了一个半透明的黑色Rectangle
。
ListModel {
id: imagePaths
}
ListView {
id: listView
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.bottomMargin: 10
height: 100
orientation: ListView.Horizontal
spacing: 10
model: imagePaths
delegate: Image {
required property string path
height: 100
source: path
fillMode: Image.PreserveAspectFit
}
Rectangle {
anchors.fill: parent
anchors.topMargin: -10
color: "black"
opacity: 0.5
}
}
对于图像的拍摄,CaptureSession
元素包含一组用于各种任务的子元素。 为了捕捉静态图片,使用了CaptureSession.imageCapture
元素。 当调用captureToFile
方法时,会拍摄一张图片并将其保存在用户的本地图片目录中,这将会导致CaptureSession.imageCapture
发出imageSaved
信号。
Button {
id: shotButton
width: parent.buttonWidth
height: parent.buttonHeight
text: qsTr("Take Photo")
onClicked: {
captureSession.imageCapture.captureToFile()
}
}
在这种情况下,不需要显示预览图像,只需将生成的图像添加到屏幕底部的ListView
即可。 如下例所示,保存图像的路径作为path
参数随信号提供。
CaptureSession {
id: captureSession
videoOutput: output
camera: Camera {}
imageCapture: ImageCapture {
onImageSaved: function (id, path) {
imagePaths.append({"path": path})
listView.positionViewAtEnd()
}
}
}
提示
要显示预览,请连接到imageCaptured
信号并使用信号参数preview
作为Image
元素的source
。信号参数id
随imageCaptured
和imageSaved
一起发送,这个值是从capture
方法返回的。 使用它,可以在整个周期中跟踪图像的捕获。 这样,可以先使用预览,然后将其替换为正确保存的图像。 然而,在示例中并不是这样做的。
# 切换相机
如果用户有多个摄像头,提供一种在这些摄像头之间切换的方法会很方便使用。 可以通过将MediaDevices
元素与ListView
结合使用来实现此目的。 在此例子中,将使用一个ComboBox
组件:
MediaDevices {
id: mediaDevices
}
ComboBox {
id: cameraComboBox
width: parent.buttonWidth
height: parent.buttonHeight
model: mediaDevices.videoInputs
textRole: "description"
displayText: captureSession.camera.cameraDevice.description
onActivated: function (index) {
captureSession.camera.cameraDevice = cameraComboBox.currentValue
}
}
ComboBox
的model
属性设置为MediaDevices
的videoInputs
属性,videoInputs
属性包含可用视频输入的列表。 然后将控件的displayText
设置为相机设备的描述(captureSession.camera.cameraDevice.description
)。
最后,当用户切换视频输入时,cameraDevice
会更新以反映该变化,即captureSession.camera.cameraDevice = cameraComboBox.currentValue
。
# 回放
应用程序的最后一部分是实际播放。 这使用Timer
元素和一些JavaScript函数驱动。 _imageIndex
变量用于跟踪当前显示的图像。 显示到最后一张图像时,播放停止。 在示例中,root.state
用于在播放序列时隐藏部分用户界面。
property int _imageIndex: -1
function startPlayback() {
root.state = "playing"
root.setImageIndex(0)
playTimer.start()
}
function setImageIndex(i) {
root._imageIndex = i
if (root._imageIndex >= 0 && root._imageIndex < imagePaths.count) {
image.source = imagePaths.get(root._imageIndex).path
} else {
image.source = ""
}
}
Timer {
id: playTimer
interval: 200
repeat: false
onTriggered: {
if (root._imageIndex + 1 < imagePaths.count) {
root.setImageIndex(root._imageIndex + 1)
playTimer.start()
} else {
root.setImageIndex(-1)
root.state = ""
}
}
}