HarmonyOS 鸿蒙Next相机预览画面如何设置随屏幕旋转而旋转?
HarmonyOS 鸿蒙Next相机预览画面如何设置随屏幕旋转而旋转?
在单框架应用中设置屏幕自动旋转,需要在模块配置文件module.json5中给EntryAbility设置"orientation": “auto_rotation”,再打开手机自动旋转即可。
以下内容是旋转过程画面会出现倒置的现象的解决方案
相机框架会根据屏幕方向、前后摄、相机安装方向,输出正立的旋转角度,xComponent预览时会使用这个角度做渲染;窗口自动旋转时,xComponent又转一次的话,必然会导致预览内容就不再是正立
import camera from '[@ohos](/user/ohos).multimedia.camera';
import image from '[@ohos](/user/ohos).multimedia.image';
import abilityAccessCtrl from '[@ohos](/user/ohos).abilityAccessCtrl';
import common from '[@ohos](/user/ohos).app.ability.common';
import fs from '[@ohos](/user/ohos).file.fs';
import {BusinessError} from '[@ohos](/user/ohos).base';
[@Entry](/user/Entry)
[@Component](/user/Component)
struct Index {
[@State](/user/State) message: string = 'Hello World'
private mXComponentController: XComponentController = new XComponentController;
private surfaceId: string = '-1';
[@State](/user/State) imgUrl: PixelMap | undefined = undefined;
private context: ESObject = undefined
private previewProfilesObj2: camera.Profile | undefined = undefined;
private receiver: image.ImageReceiver | undefined = undefined;
aboutToAppear() {
//申请权限
let context = getContext() as common.UIAbilityContext;
abilityAccessCtrl.createAtManager().requestPermissionsFromUser(context, ['ohos.permission.CAMERA']).then(() => {
this.mXComponentController.setXComponentSurfaceSize({ surfaceWidth: 1920, surfaceHeight: 1080 });
// 获取Surface ID
this.surfaceId = this.mXComponentController.getXComponentSurfaceId();
this.createDualChannelPreview(this.surfaceId);
});
console.info(`surfaceId=${this.surfaceId}`);
}
async createDualChannelPreview(XComponentSurfaceId: string): Promise<void> {
let cameraManager = await camera.getCameraManager(getContext() as ESObject);
let camerasDevices: Array<camera.CameraDevice> = cameraManager.getSupportedCameras(); // 获取支持的相机设备对象
// 获取支持的模式类型
let sceneModes: Array<camera.SceneMode> = cameraManager.getSupportedSceneModes(camerasDevices[0]);
let isSupportPhotoMode: boolean = sceneModes.indexOf(camera.SceneMode.NORMAL_PHOTO) >= 0;
if (!isSupportPhotoMode) {
console.error('photo mode not support');
return;
}
// 获取profile对象
let profiles: camera.CameraOutputCapability = cameraManager.getSupportedOutputCapability(camerasDevices[0]); // 获取对应相机设备profiles
let previewProfiles: Array<camera.Profile> = profiles.previewProfiles;
// 预览流1
let previewProfilesObj: camera.Profile = previewProfiles[0];
// 预览流2
this.previewProfilesObj2 = previewProfiles[0];
let size:image.Size = {
height: this.previewProfilesObj2.size.height,
width: this.previewProfilesObj2.size.width
}
this.receiver= image.createImageReceiver(size, image.ImageFormat.JPEG, 8)
// 创建 预览流1 输出对象
let previewOutput: camera.PreviewOutput = cameraManager.createPreviewOutput(previewProfilesObj, XComponentSurfaceId);
// 创建 预览流2 输出对象
let imageReceiverSurfaceId: string = await this.receiver.getReceivingSurfaceId();
let previewOutput2: camera.PreviewOutput = cameraManager.createPreviewOutput(this.previewProfilesObj2, imageReceiverSurfaceId);
// 创建cameraInput对象
let cameraInput: camera.CameraInput = cameraManager.createCameraInput(camerasDevices[0]);
// 打开相机
await cameraInput.open();
// 会话流程
let captureSession: camera.CaptureSession = cameraManager.createCaptureSession();
// 开始配置会话
captureSession.beginConfig();
// 把CameraInput加入到会话
captureSession.addInput(cameraInput);
// 把 预览流1 加入到会话
captureSession.addOutput(previewOutput);
// 把 预览流2 加入到会话
captureSession.addOutput(previewOutput2);
// 提交配置信息
await captureSession.commitConfig();
// 会话开始
await captureSession.start();
this.onImageArrival(this.receiver);
}
async onImageArrival(receiver: image.ImageReceiver): Promise<void> {
receiver.on('imageArrival', () => {
console.error("imageArrival callback");
receiver.readNextImage((err, nextImage: image.Image) => {
let a = nextImage.format
nextImage.getComponent(image.ComponentType.JPEG, async (err, imgComponent: image.Component) => {
if (err || imgComponent === undefined) {
return;
}
this.saveImageToFile(imgComponent.byteBuffer);
if (imgComponent.byteBuffer as ArrayBuffer) {
let sourceOptions: image.SourceOptions = {
sourceDensity: 120,
sourcePixelFormat: 8, // NV21
sourceSize: {
height: this.previewProfilesObj2!.size.height,
width: this.previewProfilesObj2!.size.width
},
}
let imageResource = image.createImageSource(imgComponent.byteBuffer, sourceOptions);
let imagePackerApi = image.createImagePacker();
let packOpts: image.PackingOption = { format: "image/jpeg", quality: 98 };
const filePath: string = getContext().cacheDir + "/image.jpg";
let file = fs.openSync(filePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
imagePackerApi.packToFile(imageResource, file.fd, packOpts).then(() => {
console.error('pack success: ' + filePath);
}).catch((error: BusinessError) => {
console.error('Failed to pack the image. And the error is: ' + error);
})
imageResource.createPixelMap({}).then((res)=>{
this.imgUrl = res;
});
} else {
return;
}
nextImage.release();
})
})
})
}
saveImageToFile(data: ArrayBuffer) {
const context = getContext(this);
let filePath = context.tempDir + "/test.jpg";
console.info("path is " + filePath);
let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
fs.write(file.fd, data, (err, writeLen) => {
if (err) {
console.info("write failed with error message: " + err.message + ", error code: " + err.code);
} else {
console.info("write data to file succeed and size is:" + writeLen);
fs.closeSync(file);
}
});
// context.tempDir + "/test.jpg" 对应绝对路径 /data/app/el2/100/base/com.example.image_example/haps/Packer/temp/test.jpg (也可通过hdc shell 查询对应目录)
// hdc file recv /data/app/el2/100/base/com.example.image_example/haps/Packer/temp/test.jpg D:\ (获取文件到本地,查看保存结果)
}
build() {
Column() {
// 创建XComponent
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();
this.createDualChannelPreview(this.surfaceId);
})
.width('1920px')
.height('1080px')
Row() {
// 将编辑好的pixelMap传递给状态变量imagePixelMap后,通过Image组件进行渲染
Image(this.imgUrl).objectFit(ImageFit.None)
}.width('100%').height('50%').backgroundColor('#F0F0F0')
}
}
}
更多关于HarmonyOS 鸿蒙Next相机预览画面如何设置随屏幕旋转而旋转?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS 鸿蒙Next系统中,要使相机预览画面随屏幕旋转而旋转,可以通过调整相机的预览显示方向来实现。具体步骤如下:
-
获取屏幕旋转角度: 使用系统提供的传感器或API,实时获取设备的屏幕旋转角度(如0度、90度、180度、270度)。
-
调整相机预览方向: 根据获取到的屏幕旋转角度,动态调整相机的预览方向。这通常涉及对相机预览帧的旋转处理。
-
更新UI布局: 在检测到屏幕旋转事件后,及时更新相机的预览UI布局,确保预览画面与屏幕方向一致。
-
确保相机资源释放: 在屏幕旋转过程中,注意正确释放和重新获取相机资源,避免资源泄露或应用崩溃。
-
适配不同屏幕尺寸: 考虑不同屏幕尺寸和分辨率的适配问题,确保相机预览画面在各种设备上都能正确显示。
综上所述,通过获取屏幕旋转角度、调整相机预览方向、更新UI布局以及确保资源正确释放,可以实现HarmonyOS 鸿蒙Next相机预览画面随屏幕旋转而旋转的功能。如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html。