
import { BusinessError } from '@kit.BasicServicesKit';
import { abilityAccessCtrl, common } from '@kit.AbilityKit';
import { camera } from '@kit.CameraKit';
import { image } from '@kit.ImageKit';
/**
* YUV数据旋转函数,在onImageArrival回调时调用得到新的buffer
* @param arr 需要旋转的buffer数据
* @param imageWidth 图片宽度
* @param imageHeight 图片高度
* @returns 旋转90度后的buffer数据
*/
export function rotateYUVDegree90(arr: ArrayBuffer, imageWidth: number, imageHeight: number): ArrayBuffer {
let yuv: Uint8Array = new Uint8Array(imageWidth * imageHeight * 3 / 2);
let data: Uint8Array = new Uint8Array(arr);
let i = 0;
// 将Y分量进行旋转
for (let x = 0; x < imageWidth; x++) {
for (let y = imageHeight - 1; y >= 0; y--) {
yuv[i] = data[y * imageWidth + x];
i++;
}
}
// 将颜色分量U、V进行旋转
i = imageWidth * imageHeight * 3 / 2 - 1;
for (let x = imageWidth - 1; x > 0; x = x - 2) {
for (let y = 0; y < imageHeight / 2; y++) {
yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + x];
i--;
yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + (x - 1)];
i--;
}
}
return yuv.buffer;
}
@Entry
@Component
struct Index {
@State imgUrl: PixelMap | undefined = undefined;
private flag: boolean = true;
private photoOutput: camera.PhotoOutput | undefined = undefined;
private captureSession: camera.Session | undefined = undefined;
private context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
private previewProfilesObj2: camera.Profile | undefined = undefined;
private receiver: image.ImageReceiver | undefined = undefined;
aboutToAppear() {
abilityAccessCtrl.createAtManager()
.requestPermissionsFromUser(this.getUIContext().getHostContext(), ['ohos.permission.CAMERA'])
.then(() => {
this.createDualChannelPreview();
});
}
onPageShow(): void {
this.createDualChannelPreview();
}
async createDualChannelPreview(): Promise<void> {
let cameraManager: camera.CameraManager = camera.getCameraManager(this.context);
// 获取支持的相机设备对象
let camerasDevices: Array<camera.CameraDevice> = cameraManager.getSupportedCameras();
// 获取profile对象
let profiles: camera.CameraOutputCapability =
cameraManager.getSupportedOutputCapability(camerasDevices[0], camera.SceneMode.NORMAL_PHOTO);
let previewProfiles: Array<camera.Profile> = profiles.previewProfiles;
// 预览流2
this.previewProfilesObj2 = previewProfiles[0];
this.receiver = image.createImageReceiver(this.previewProfilesObj2.size, 2000, 8);
// 创建预览流2输出对象
let imageReceiverSurfaceId: string = await this.receiver.getReceivingSurfaceId();
let previewOutput2: camera.PreviewOutput =
cameraManager.createPreviewOutput(this.previewProfilesObj2, imageReceiverSurfaceId);
let photoProfilesArray: Array<camera.Profile> = profiles.photoProfiles;
try {
this.photoOutput = cameraManager.createPhotoOutput(photoProfilesArray[0]);
} catch (error) {
let err = error as BusinessError;
console.error(`Create photoOutput error: ${err.code}`);
}
if (this.photoOutput === undefined) {
return;
}
// 创建cameraInput对象
let cameraInput: camera.CameraInput = cameraManager.createCameraInput(camerasDevices[0]);
// 打开相机
await cameraInput.open();
// 会话流程
this.captureSession = cameraManager.createSession(1);
// 开始配置会话
this.captureSession.beginConfig();
// 把CameraInput加入到会话
this.captureSession.addInput(cameraInput);
// 把预览流2加入到会话
this.captureSession.addOutput(previewOutput2);
try {
this.captureSession.addOutput(this.photoOutput);
} catch (error) {
let err = error as BusinessError;
console.error(`Add photoOutput error: ${err.code}}`);
}
// 提交配置信息
await this.captureSession.commitConfig();
// 会话开始
await this.captureSession.start();
this.onImageArrival(this.receiver);
}
async onImageArrival(receiver: image.ImageReceiver): Promise<void> {
// Image格式与PixelMap格式映射关系。
let formatToPixelMapFormatMap = new Map<number, image.PixelMapFormat>([
[12, image.PixelMapFormat.RGBA_8888],
[25, image.PixelMapFormat.NV21],
[35, image.PixelMapFormat.YCBCR_P010],
[36, image.PixelMapFormat.YCRCB_P010]
]);
// PixelMapFormat格式的单个像素点大小映射关系。
let pixelMapFormatToSizeMap = new Map<image.PixelMapFormat, number>([
[image.PixelMapFormat.RGBA_8888, 4],
[image.PixelMapFormat.NV21, 1.5],
[image.PixelMapFormat.YCBCR_P010, 3],
[image.PixelMapFormat.YCRCB_P010, 3]
]);
receiver.on('imageArrival', () => {
console.info('imageArrival 接收图片触发');
receiver.readLatestImage((err, nextImage: image.Image) => {
if (err || nextImage === undefined) {
return;
}
nextImage.getComponent(image.ComponentType.JPEG, (err, imgComponent: image.Component) => {
if (err || imgComponent === undefined) {
return;
}
if (this.flag) {
if (imgComponent.byteBuffer as ArrayBuffer) {
let width = nextImage.size.width; // 获取图片的宽。
let height = nextImage.size.height; // 获取图片的高。
let stride = imgComponent.rowStride; // 获取图片的stride。
let imageFormat = nextImage.format; // 获取图片的format。
let pixelMapFormat = formatToPixelMapFormatMap.get(imageFormat) ?? image.PixelMapFormat.NV21;
let mSize = pixelMapFormatToSizeMap.get(pixelMapFormat) ?? 1.5;
let sourceOptions: image.SourceOptions = {
sourceDensity: 120,
sourcePixelFormat: 8,
sourceSize: {
height: this.previewProfilesObj2!.size.height,
width: this.previewProfilesObj2!.size.width
},
};
let decodingOptions: image.DecodingOptions = {
editable: true,
desiredPixelFormat: 3,
};
if (stride == width) {
// 调用旋转函数
let buffer: ArrayBuffer =
rotateYUVDegree90(imgComponent.byteBuffer, this.previewProfilesObj2!.size.width,
this.previewProfilesObj2!.size.height);
let imageResource = image.createImageSource(buffer, sourceOptions);
imageResource.createPixelMap(decodingOptions).then((res) => {
this.imgUrl = res;
});
} else { // stride与width不一致。
const dstBufferSize = width * height * mSize;
const dstArr = new Uint8Array(dstBufferSize);
for (let j = 0; j < height * mSize; j++) {
const srcBuf = new Uint8Array(imgComponent.byteBuffer, j * stride, width);
dstArr.set(srcBuf, j * width);
}
// 调用旋转函数
let buffer: ArrayBuffer =
rotateYUVDegree90(dstArr.buffer as ArrayBuffer, this.previewProfilesObj2!.size.width,
this.previewProfilesObj2!.size.height);
let imageResource = image.createImageSource(buffer, sourceOptions);
imageResource.createPixelMap(decodingOptions).then((res) => {
this.imgUrl = res;
});
}
} else {
return;
}
}
nextImage.release();
});
});
});
}
build() {
Column() {
Row() {
// 将编辑好的pixelMap传递给状态变量imgUrl后,通过Image组件进行渲染
Image(this.imgUrl).objectFit(ImageFit.Cover).width('100%').height('50%')
}.backgroundColor('#F0F0F0')
Row({ space: 20 }) {
Button('暂停预览').onClick(() => {
this.flag = false;
})
.width(100)
.height(100)
Button('继续预览').onClick(() => {
this.flag = true;
})
.width(100)
.height(100)
}
.margin({ top: 20 })
}
}
} 旋转之后的预览图像如下图所示:
