前言
本小节实现qml中摄像头的图片保存,最终效果为在系统相册中可以看到图片文件。
功能比较简单,直接记录一下。
一、摄像头图片捕获
在我当前开发版本(Qt6.10)中,关于qml的摄像头拍照保存,主要依赖ImageCapture对象,需要创建其实例,并设置给CaptureSession对象。
cpp
CaptureSession {
id: captureSession
camera: cameraId
videoOutput: videoOutput
imageCapture: imageCapture
}
Camera {
id: cameraId
focusMode: Camera.FocusModeAutoNear
onErrorOccurred: console.log("Camera error:", errorString)
}
ImageCapture {
id: imageCapture
quality: ImageCapture.HighQuality
onImageSaved: (requestId, savedPath) => {
console.log("✅ 照片已保存到:", savedPath);
}
}
使用时,主要调用capture相关方法,最终会触发onImageSaved等结果回调,感兴趣的可以查看ImageCapture 的帮助文档。
在我的代码中,通过按钮触发,调用ImageCapture 对象的captureToFile方法,顾名思义,它可以保存成真实存在于手机系统中的图片文件。如果只是调用capture方法的话,只是暂时存放于内存中,设置了预览Image的话会显示出来而已。
代码如下:
cpp
function takePhoto() {
if (!cameraId.active) {
infoBanner.text = "⚠️ 请先启动相机";
infoBanner.visible = true;
infoTimer.restart();
return;
}
// 👇 生成目标路径(公共 Pictures 目录)
const now = new Date();
const timestamp = Qt.formatDateTime(now, "yyyyMMdd_hhmmss");
const fileName = "Photo_" + timestamp + ".jpg";
const destPath = FileHelper.getPublicPicturesPath() + "/" + fileName;
console.log("📸 拍照并保存到:", destPath);
imageCapture.captureToFile(destPath); // ← 关键修改!
}
这里给captureToFile设置了一个图片路径,包含了使用时间戳生成的图片名称。
二、获取合适的保存路径
这里介绍一下FileHelper.getPublicPicturesPath(),FileHelper是暴露给qml全局的上下文属性对象,调用getPublicPicturesPath接口的目的是为了获取图片保存路径。
在第一次尝试中,我将图片保存在软件临时目录下。结果是能在目录中找到图片文件,但在系统相册中没有找到。原因是较高安卓版本中,系统相册不会去寻找软件临时目录下的文件。
cpp
QString FileHelper::getPublicPicturesPath() const
{
// 公共 Pictures 目录: /sdcard/Pictures/TestProjectQMake/
QString path = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)
+ "/TestProjectQMake";
QDir dir(path);
if (!dir.exists()) {
dir.mkpath(".");
}
return path;
}
路径是这样的:/storage/emulated/0/Android/data/org.qtproject.example.TestProjectQMake/files/Pictures/TestProjectQMake/Photo_20260209_142630.jpg
为了将文件保存在公共目录中,进行了第二次尝试。
cpp
QString FileHelper::getPublicPicturesPath() const
{
#ifdef Q_OS_ANDROID
// ✅ 正确方式:获取 android.os.Environment.DIRECTORY_PICTURES 的值
QJniObject directoryPictures = QJniObject::getStaticObjectField(
"android/os/Environment",
"DIRECTORY_PICTURES",
"Ljava/lang/String;");
if (directoryPictures.isValid()) {
QJniObject publicDir = QJniObject::callStaticObjectMethod(
"android/os/Environment",
"getExternalStoragePublicDirectory",
"(Ljava/lang/String;)Ljava/io/File;",
directoryPictures.object<jstring>());
if (publicDir.isValid()) {
QString path = publicDir.callObjectMethod("getAbsolutePath", "()Ljava/lang/String;").toString();
QDir dir(path + "/TestProjectQMake");
if (!dir.exists()) {
dir.mkpath(".");
}
return path + "/TestProjectQMake";
}
}
#endif
// fallback(非 Android 或失败)
QString path = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
QDir dir(path + "/TestProjectQMake");
if (!dir.exists()) {
dir.mkpath(".");
}
return path + "/TestProjectQMake";
}
这段是ai写的,最终生成的路径是:/storage/emulated/0/Pictures/TestProjectQMake
简单来说,就是调用 Android API 获取公共目录,通过Environment系统类定义耳朵一个常量:public static final String DIRECTORY_PICTURES = "Pictures";再增加软件名子文件夹,将图片保存到该目录下。
实际测试中,能从该目录下找到文件,在系统相册中亦能显示该图片,符合我的功能预期。
三、总结
即便已经是高版本qt,但我觉得qml中对于摄像头的图片保存还是显得复杂。毕竟保存方法是在qml中,总感觉如果想转换到C++中实现保存操作挺别扭的。比如qml中保存了图片,但我需要将它发送到C++侧,利用QImage实现亮度修改、图片翻转等操作的时候。
但文件的保存是通用的,虽然还没有尝试,但只要路径正确,调用QImage的保存方法应该也是Ok的。值得一提的是,ai给我考虑了不少安卓权限的问题,但实际开发中我都没有遇到,代码正确就直接成功了。应该是高版本qt已经做了不少适配,生成的权限文件中已经自带了大部分常用权限,这极大方便了我们开发者。