Qt安卓开发(四)摄像头拍照保存

前言

本小节实现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已经做了不少适配,生成的权限文件中已经自带了大部分常用权限,这极大方便了我们开发者。

相关推荐
北冥you鱼几秒前
Go 语言读取链上数据:从基础到实战
开发语言·后端·golang
nianniannnn1 分钟前
c++复习自存--继承
开发语言·c++
HERR_QQ11 分钟前
强化学习的数学原理 学习笔记
人工智能·笔记·学习·自动驾驶
安卓修改大师16 分钟前
安卓修改大师反编译引擎Apktool深度解析:版本选择、参数说明与实战技巧
android
小短腿的代码世界26 分钟前
Qt WebEngine多进程架构与IPC通信:从Chromium多进程到Qt信号槽融合
qt·架构·系统架构
error:(29 分钟前
【系统与实战双精通】VS Code 调试 ROS2 Python 节点与 Launch 系统指南
android·java·python
MartinYeung51 小时前
[论文学习]DP-Fusion:面向大语言模型的令牌级差分隐私推理-深度解析
人工智能·学习·语言模型
叩码以求索1 小时前
经典算法实例分析:写字符串需要的行数
开发语言·javascript·ecmascript
我是唐青枫1 小时前
Kotlin 运算符重载详解:为什么 a += b 有时改对象,有时换对象?
开发语言·kotlin
2zcode1 小时前
基于MATLAB图像处理的饮料瓶识别与价格显示系统设计与实现
开发语言·图像处理·matlab