HarmonyOS 鸿蒙Next 相机拍照获取YUV数据
HarmonyOS 鸿蒙Next 相机拍照获取YUV数据
const Camera_Profile *profile = cameraOutputCapability_->photoProfiles[i];获取到的配置文件只有jpeg。是否有什么其他方法可以获取到相机拍照后的yuv数据?
获取预览数据参考相机双路预览官方文档,官方示例代码中的bytebuffer就是Yuv数据
参考:双路预览(ArkTS)-相机最佳实践(ArkTS)-Camera Kit(相机服务)-媒体 - 华为HarmonyOS开发者
参考以下代码:
import { camera } from '[@kit](/user/kit).CameraKit';
import { BusinessError } from '[@kit](/user/kit).BasicServicesKit';
import { image } from '[@kit](/user/kit).ImageKit';
import { photoAccessHelper } from '[@kit](/user/kit).MediaLibraryKit';
import { abilityAccessCtrl, PermissionRequestResult, Permissions } from '[@kit](/user/kit).AbilityKit';
import { promptAction, router } from '[@kit](/user/kit).ArkUI';
import { fileIo } from '[@kit](/user/kit).CoreFileKit';
const TAG = '[CameraDemo]';
struct CameraDemo {
context: Context = getContext(this) as Context;
[@State](/user/State) pixelMap: image.PixelMap | undefined = undefined;
[@State](/user/State) finalPixelMap: image.PixelMap | undefined = undefined;
[@State](/user/State) buffer: ArrayBuffer | undefined = undefined;
[@State](/user/State) surfaceId: string = '';
[@State](/user/State) hasPicture: boolean = false;
[@State](/user/State) fileNames: string[] = [];
[@State](/user/State) imageSize: image.Size = { width: 1920, height: 1080 };
[@State](/user/State) saveButtonOptions: SaveButtonOptions = {
icon: SaveIconStyle.FULL_FILLED,
text: SaveDescription.SAVE_IMAGE,
buttonType: ButtonType.Capsule
}
//设置安全控件按钮属性
private mXComponentController: XComponentController = new XComponentController;
private cameraManager: camera.CameraManager | undefined = undefined;
private cameraSession: camera.PhotoSession | undefined = undefined;
private photoOutput: camera.PhotoOutput | undefined = undefined;
private cameraInput: camera.CameraInput | undefined = undefined;
private previewOutput: camera.PreviewOutput | undefined = undefined;
private imageReceiver: image.ImageReceiver | undefined = undefined;
aboutToAppear(): void {
let permissions: Array<Permissions> = [
'ohos.permission.CAMERA',
'ohos.permission.WRITE_MEDIA',
'ohos.permission.READ_MEDIA',
'ohos.permission.MEDIA_LOCATION',
];
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
//requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗
atManager.requestPermissionsFromUser(this.context, permissions).then((data: PermissionRequestResult) => {
let grantStatus: Array<number> = data.authResults;
let length: number = grantStatus.length;
for (let i = 0; i < length; i++) {
if (grantStatus[i] != 0) {
//用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限
return;
}
}
console.info(`${TAG} Success to request permissions from user. authResults is ${grantStatus}.`);
}).catch((err: BusinessError) => {
console.error(`${TAG} Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
})
}
createCameraManager() {
//创建CameraManager对象
let cameraManager: camera.CameraManager = camera.getCameraManager(this.context);
if (!cameraManager) {
console.error('CameraDemo camera.getCameraManager error');
return;
}
this.cameraManager = cameraManager
//监听相机状态变化
this.cameraManager.on('cameraStatus', (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo) => {
console.info(`CameraDemo camera: ${cameraStatusInfo.camera.cameraId}, status: ${cameraStatusInfo.status}`);
});
}
build() {
Column() {
Column({ space: 20 }) {
if (this.hasPicture) {
Image(this.finalPixelMap)
.objectFit(ImageFit.Fill)
.width('100%')
.height(300)
//创建安全控件按钮
SaveButton(this.saveButtonOptions)
.onClick(async (event, result: SaveButtonOnClickResult) => {
if (result == SaveButtonOnClickResult.SUCCESS) {
if (this.finalPixelMap) {
try {
//1、使用安全控件创建文件
let phAccessHelper: photoAccessHelper.PhotoAccessHelper = photoAccessHelper.getPhotoAccessHelper(this.context);
let options: photoAccessHelper.CreateOptions = {
title: Date.now().toString()
};
//createAsset的调用需要ohos.permission.READ_IMAGEVIDEO和ohos.permission.WRITE_IMAGEVIDEO的权限
let photoUri: string = await phAccessHelper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'png', options);
console.info('CameraDemo createAsset successfully, photoUri: ' + photoUri);
let file: fileIo.File = fileIo.openSync(photoUri, fileIo.OpenMode.WRITE_ONLY);
fileIo.writeSync(file.fd, this.buffer);
fileIo.closeSync(file);
promptAction.showToast({message:`保存成功`})
} catch (error) {
let err = error as BusinessError;
console.error(`CameraDemo savePicture error: ${JSON.stringify(err)}`);
promptAction.showToast({ message:`保存失败` })
}
}
} else {
console.error('CameraDemo SaveButtonOnClickResult createAsset failed.');
promptAction.showToast({ message:`保存失败` })
}
setTimeout(() => {
this.hasPicture = false;
this.finalPixelMap = undefined;
}, 1000)
})
} else {
XComponent({
id: '',
type: 'surface',
libraryname: '',
controller: this.mXComponentController
})
.onLoad(() => {
//设置Surface宽高(1920*1080),预览尺寸设置参考前面 previewProfilesArray 获取的当前设备所支持的预览分辨率大小去设置
//预览流与录像输出流的分辨率的宽高比要保持一致
this.mXComponentController.setXComponentSurfaceSize({ surfaceWidth: 1920, surfaceHeight: 1080 });
//获取Surface ID
this.surfaceId = this.mXComponentController.getXComponentSurfaceId();
setTimeout(async () => {
await this.prepareCamera();
}, 500);
})
.width('100%')
.height(600)
Button('拍照')
.width(200)
.height(30)
.onClick(async () => {
let photoCaptureSetting: camera.PhotoCaptureSetting = {
quality: camera.QualityLevel.QUALITY_LEVEL_HIGH, // 设置图片质量高
rotation: camera.ImageRotation.ROTATION_0 // 设置图片旋转角度0
}
// 1、通过拍照流实现:点击拍照
await this.photoOutput?.capture(photoCaptureSetting).catch((error: BusinessError) => {
console.error(`CameraDemo Failed to capture the photo ${error.message}`); //不符合条件则进入
})
this.hasPicture = true;
})
}
}
.width('100%')
.height('100%')
.padding(15)
.borderRadius(8)
}
.width('100%')
.height('100%')
.backgroundColor('#FFFFFF')
}
async prepareCamera() {
this.createCameraManager();
if (!this.cameraManager) {
console.error('CameraDemo cameraManager is undefined.')
return;
}
//获取支持指定的相机设备对象
let cameraDevices: Array<camera.CameraDevice> = [];
try {
cameraDevices = this.cameraManager.getSupportedCameras();
} catch (error) {
let err = error as BusinessError;
console.error(`CameraDemo The getSupportedCameras call failed. error: ${JSON.stringify(err)}`)
}
cameraDevices.forEach((cameraDevice: camera.CameraDevice) => {
console.info(`CameraDemo cameraId: ${cameraDevice.cameraId}, cameraPosition: ${cameraDevice.cameraPosition.toString()}, cameraType: ${cameraDevice.cameraType.toString()}, connectionType: ${
更多关于HarmonyOS 鸿蒙Next 相机拍照获取YUV数据的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
预览我能拿到,但是拍照不行吧
找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17
试一下呢~
我试过啊,不是一开始就写了么,创建PhotoOutput 的时候传入获取到的系统的拍照photoProfiles里面就没有yuv。但是这个东西华为肯定是支持的,就是没开放给三方或者有一些其他骚操作、
在HarmonyOS鸿蒙Next系统中,相机拍照并获取YUV数据的过程主要涉及到相机API的使用和图像处理。以下是一个简要的步骤概述:
-
权限申请:首先,确保你的应用已申请并获得了相机和存储权限。
-
相机初始化:使用
CameraKit
进行相机的初始化,包括设置预览和拍照的回调。 -
设置预览回调:通过
CameraCaptureCallback
设置预览回调,虽然这一步不是直接获取YUV数据,但它是相机功能的基础。 -
配置拍照参数:在拍照前,通过
CameraCaptureConfig
配置拍照参数,包括图像格式。为了获取YUV数据,需要指定图像格式为ImageFormat.YUV_420_888
。 -
拍照并获取数据:调用
capturePhoto
方法进行拍照,并在回调中处理数据。在回调的onCaptureCompleted
方法中,你可以获取到拍照的CaptureResult
,其中包含图像的ByteBuffer
数据。 -
处理YUV数据:从
ByteBuffer
中提取YUV数据,进行后续处理或保存。
注意,处理YUV数据需要一定的图像处理知识,因为它包含亮度(Y)和色度(U/V)分量,需要正确解析和处理。
如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html