本文同步发表于微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

一、拍照方案

1.1 两种拍照方案

方案 特点 出图速度 画质 适用场景
分段式拍照 先输出低质量图(缩略图),后输出高质量图 图像处理算法需求,提升用户体验
单段式拍照 多帧融合+底层算法处理后返回一张高质量图 较慢 画质优先场景,支持高性能拍照设置

备注:本文以单段式拍照为基础进行说明。

1.2 高性能拍照

从API version 21开始,单段式拍照支持设置画质优先策略,可调整:

  • 出图速度:街头抓拍等场景

  • 图片质量:风景或人像拍摄等场景

二、开发步骤

2.1 导入相关模块

import { image } from '@kit.ImageKit';
import { camera } from '@kit.CameraKit';
import { fileIo as fs } from '@kit.CoreFileKit';
import { BusinessError } from '@kit.BasicServicesKit';

2.2 创建拍照输出流

通过CameraOutputCapability中的photoProfiles属性获取当前设备支持的拍照输出流,然后通过createPhotoOutput创建拍照输出流。

function getPhotoOutput(cameraManager: camera.CameraManager, 
                        cameraOutputCapability: camera.CameraOutputCapability): camera.PhotoOutput | undefined {
    let photoProfilesArray: Array<camera.Profile> = cameraOutputCapability.photoProfiles;
    
    if (!photoProfilesArray || photoProfilesArray.length === 0) {
        console.error("photoProfilesArray is null or []");
        return;
    }
    
    let photoOutput: camera.PhotoOutput | undefined;
    try {
        photoOutput = cameraManager.createPhotoOutput(photoProfilesArray[0]);
    } catch (error) {
        let err = error as BusinessError;
        console.error(`Failed to createPhotoOutput. error: ${err}`);
    }
    
    return photoOutput;
}

2.3 设置拍照回调

设置on('photoAvailable')回调,当拍照完成时将buffer保存为图片。

function setPhotoOutputCb(photoOutput: camera.PhotoOutput): void {
    photoOutput.on('photoAvailable', (errCode: BusinessError, photo: camera.Photo): void => {
        console.info('getPhoto start');
        
        if (errCode || photo === undefined) {
            console.error('getPhoto failed, err: ${errCode}');
            return;
        }
        
        let imageObj: image.Image = photo.main;
        
        imageObj.getComponent(image.ComponentType.JPEG, (errCode: BusinessError, component: image.Component): void => {
            console.info('getComponent start');
            
            if (errCode || component === undefined) {
                console.error('getComponent failed');
                return;
            }
            
            let buffer: ArrayBuffer;
            if (component.byteBuffer) {
                buffer = component.byteBuffer;
            } else {
                console.error('byteBuffer is null');
                return;
            }
            
            // 保存图片到媒体库(建议使用安全控件SaveButton)
            // 处理结束后释放资源
            imageObj.release();
        });
    });
}

重要:buffer处理结束后需要释放资源,如果未正确释放会导致后续拍照获取不到buffer。

2.4 参数配置

配置相机的闪光灯、变焦、对焦等参数。

function configuringSession(photoSession: camera.PhotoSession): void {
    // 1. 判断设备是否支持闪光灯
    let flashStatus: boolean = false;
    try {
        flashStatus = photoSession.hasFlash();
    } catch (error) {
        let err = error as BusinessError;
        console.error(`Failed to hasFlash. error: ${err}`);
    }
    console.info(`Flash light support status: ${flashStatus}`);
    
    if (flashStatus) {
        // 判断是否支持自动闪光灯模式
        let flashModeStatus: boolean = false;
        try {
            flashModeStatus = photoSession?.isFlashModeSupported(camera.FlashMode.FLASH_MODE_AUTO);
        } catch (error) {
            let err = error as BusinessError;
            console.error(`Failed to check flash mode support. error: ${err}`);
        }
        
        if (flashModeStatus) {
            // 设置自动闪光灯模式
            try {
                photoSession?.setFlashMode(camera.FlashMode.FLASH_MODE_AUTO);
            } catch (error) {
                let err = error as BusinessError;
                console.error(`Failed to set flash mode. error: ${err}`);
            }
        }
    }
    
    // 2. 判断是否支持连续自动对焦模式
    let focusModeStatus: boolean = false;
    try {
        focusModeStatus = photoSession?.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO);
    } catch (error) {
        let err = error as BusinessError;
        console.error(`Failed to check focus mode support. error: ${err}`);
    }
    
    if (focusModeStatus) {
        // 设置连续自动对焦模式
        try {
            photoSession?.setFocusMode(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO);
        } catch (error) {
            let err = error as BusinessError;
            console.error(`Failed to set focus mode. error: ${err}`);
        }
    }
    
    // 3. 获取相机支持的可变焦距比范围
    let zoomRatioRange: Array<number> = [];
    try {
        zoomRatioRange = photoSession?.getZoomRatioRange();
    } catch (error) {
        let err = error as BusinessError;
        console.error(`Failed to get zoom ratio range. error: ${err}`);
    }
    
    if (zoomRatioRange.length <= 0) {
        return;
    }
    
    // 设置可变焦距比
    try {
        photoSession?.setZoomRatio(zoomRatioRange[0]);
    } catch (error) {
        let err = error as BusinessError;
        console.error(`Failed to set zoom ratio. error: ${err}`);
    }
}

2.5 触发拍照

通过photoOutput.capture方法执行拍照任务。

function capture(captureLocation: camera.Location, photoOutput: camera.PhotoOutput): void {
    let settings: camera.PhotoCaptureSetting = {
        quality: camera.QualityLevel.QUALITY_LEVEL_HIGH,  // 设置图片质量高
        rotation: camera.ImageRotation.ROTATION_0,       // 设置图片旋转角度
        location: captureLocation,                        // 设置图片地理位置
        mirror: false                                    // 设置镜像使能开关(默认关)
    };
    
    try {
        photoOutput.capture(settings, (err: BusinessError) => {
            if (err) {
                console.error(`Failed to capture the photo. error: ${err}`);
                return;
            }
            console.info('Photo capture request success.');
        });
    } catch (error) {
        console.error(`capture call failed. error: ${error}`);
    }
}

PhotoCaptureSetting参数

参数 类型 说明
quality QualityLevel 图片质量(低/中/高)
rotation ImageRotation 图片旋转角度
location Location 图片地理位置信息
mirror boolean 镜像使能开关(默认关)

三、高性能拍照(API 21+)

3.1 画质优先策略

单段式拍照支持两种画质优先策略:

策略 枚举值 说明
速度优先 SPEED 降低画质来提升拍照速度(默认)
画质优先 HIGH_QUALITY 通过较长耗时得到更高画质的图片

注意:仅单段式拍照支持设置画质优先策略。若在分段式拍照中设置,该设置将无效。

3.2 设置画质优先策略的接口

接口 说明
isPhotoQualityPrioritizationSupported 查询当前设备是否支持指定的画质优先策略
setPhotoQualityPrioritization 设置画质优先策略

3.3 调用时机

高性能拍照相关接口需要在会话管理流程的使能步骤中调用。

方式一:在commitConfig之后调用
async function startSession(videoSession: camera.VideoSession,
                            cameraInput: camera.CameraInput,
                            previewOutput: camera.PreviewOutput,
                            photoOutput: camera.PhotoOutput): Promise<void> {
    // ... 添加输入输出流 ...
    
    try {
        await videoSession.commitConfig();
    } catch (error) {
        console.error(`Failed to commitConfig. error: ${error}`);
        return;
    }
    
    try {
        await videoSession.start();
    } catch (error) {
        console.error(`Failed to start. error: ${error}`);
    }
    
    // commitConfig之后调用
    modeSwitchToHigh(videoSession, photoOutput);
}

async function modeSwitchToHigh(videoSession: camera.VideoSession,
                                photoOutput: camera.PhotoOutput): Promise<void> {
    try {
        if (videoSession) {
            let quality: camera.PhotoQualityPrioritization = 
                camera.PhotoQualityPrioritization.HIGH_QUALITY;
            
            let isSupported = photoOutput.isPhotoQualityPrioritizationSupported(quality);
            if (isSupported) {
                photoOutput.setPhotoQualityPrioritization(quality);
            } else {
                console.error(`session is not supported`);
            }
        }
    } catch {
        console.error(`catch error`);
    }
}
方式二:在commitConfig之前调用
async function startSession(videoSession: camera.VideoSession,
                            cameraInput: camera.CameraInput,
                            previewOutput: camera.PreviewOutput,
                            photoOutput: camera.PhotoOutput): Promise<void> {
    // ... 添加输入输出流 ...
    
    // commitConfig之前调用
    modeSwitchToHigh(videoSession, photoOutput);
    
    try {
        await videoSession.commitConfig();
    } catch (error) {
        console.error(`Failed to commitConfig. error: ${error}`);
        return;
    }
    
    try {
        await videoSession.start();
    } catch (error) {
        console.error(`Failed to start. error: ${error}`);
    }
}

四、状态监听

4.1 监听拍照开始

function onPhotoOutputCaptureStart(photoOutput: camera.PhotoOutput): void {
    photoOutput.on('captureStartWithInfo', (err: BusinessError, captureStartInfo: camera.CaptureStartInfo) => {
        if (err !== undefined && err.code !== 0) {
            return;
        }
        console.info(`photo capture started, captureId: ${captureStartInfo.captureId}`);
    });
}

4.2 监听拍照结束

function onPhotoOutputCaptureEnd(photoOutput: camera.PhotoOutput): void {
    photoOutput.on('captureEnd', (err: BusinessError, captureEndInfo: camera.CaptureEndInfo) => {
        if (err !== undefined && err.code !== 0) {
            return;
        }
        console.info(`photo capture end, captureId: ${captureEndInfo.captureId}`);
        console.info(`frameCount: ${captureEndInfo.frameCount}`);
    });
}

4.3 监听可拍下一张

function onPhotoOutputCaptureReady(photoOutput: camera.PhotoOutput): void {
    photoOutput.on('captureReady', (err: BusinessError) => {
        if (err !== undefined && err.code !== 0) {
            return;
        }
        console.info(`photo capture ready`);
    });
}

4.4 监听错误

function onPhotoOutputError(photoOutput: camera.PhotoOutput): void {
    photoOutput.on('error', (error: BusinessError) => {
        console.error(`Photo output error code: ${error.code}`);
    });
}

五、开发流程

导入模块
    ↓
创建拍照输出流(createPhotoOutput)
    ↓
设置拍照回调(on('photoAvailable'))
    ↓
配置相机参数(闪光灯、对焦、变焦等)
    ↓
(可选)设置画质优先策略(高性能拍照)
    ↓
触发拍照(capture)
    ↓
监听拍照状态(开始、结束、错误)
    ↓
保存图片到媒体库
    ↓
释放资源

六、注意事项

6.1 资源释放

重要:buffer处理结束后需要释放资源,如果未正确释放资源会导致后续拍照获取不到buffer。

6.2 图片保存

如需要在图库中看到所保存的图片、视频资源,需要将其保存到媒体库,保存方式请参考:保存媒体库资源

6.3 旋转角度

获取拍照旋转角度的方法为:通过PhotoOutput中的getPhotoRotation方法获取rotation实际的值。

   鸿蒙相机拍照支持分段式拍照和单段式拍照,通过PhotoOutput创建拍照输出流、配置闪光灯/对焦/变焦等参数、调用capture触发拍照,API 21+支持设置画质优先策略以平衡出图速度和图片质量。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐