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

相关推荐
ZHOUPUYU8 小时前
PHP 8.3网关优化:我用JIT将QPS提升300%的真实踩坑录
开发语言·php
寻寻觅觅☆12 小时前
东华OJ-基础题-106-大整数相加(C++)
开发语言·c++·算法
fpcc12 小时前
并行编程实战——CUDA编程的Parallel Task类型
c++·cuda
l1t12 小时前
在wsl的python 3.14.3容器中使用databend包
开发语言·数据库·python·databend
今天只学一颗糖12 小时前
1、《深入理解计算机系统》--计算机系统介绍
linux·笔记·学习·系统架构
赶路人儿13 小时前
Jsoniter(java版本)使用介绍
java·开发语言
testpassportcn13 小时前
AWS DOP-C02 認證完整解析|AWS DevOps Engineer Professional 考試
网络·学习·改行学it
冬奇Lab13 小时前
Android系统启动流程深度解析:从Bootloader到Zygote的完整旅程
android·源码阅读
ceclar12313 小时前
C++使用format
开发语言·c++·算法
码说AI14 小时前
python快速绘制走势图对比曲线
开发语言·python