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

相关推荐
雨白3 小时前
Android 快捷方式实战指南:静态、动态与固定快捷方式详解
android
hqk3 小时前
鸿蒙项目实战:手把手带你实现 WanAndroid 布局与交互
android·前端·harmonyos
LING3 小时前
RN容器启动优化实践
android·react native
恋猫de小郭6 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
樱木Plus9 小时前
深拷贝(Deep Copy)和浅拷贝(Shallow Copy)
c++
Kapaseker11 小时前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴11 小时前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭21 小时前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab1 天前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe1 天前
Now in Android 架构模式全面分析
android·android jetpack