应用在平板设备上的拍照取景框发生了旋转
===================

#### 问题现象

用户使用相机预览时，发现界面在手机上显示正常，但在平板上却出现了90度旋转的情况。

#### 背景知识

*   开发者可以使用[PhotoCaptureSetting](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-camera-i#photocapturesetting)进行拍摄照片的设置。
*   可以对[ImageRotation](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-camera-e#imagerotation)进行设置，将预览流进行旋转。

#### 问题定位

1.  检查代码中XComponent预览流组件是否设置[rotate](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-attributes-transformation#rotate)属性，针对不同设备主动旋转角度调整组件方向。
2.  检查代码中是否使用[setXComponentSurfaceRotation](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-xcomponent#setxcomponentsurfacerotation12)锁定Surface旋转方向，使其不跟随屏幕方向变化。

#### 分析结论

平板的传感器方向与手机传感器方向不同，应用未手动设置rotate属性调整平板设备下XComponent组件的方向，导致在平板下，图像预览发生旋转。

#### 修改建议

屏幕方向锁定，当XComponent类型为SURFACE("surface")时，使用setXComponentSurfaceRotation设置XComponent使Surface在屏幕旋转时锁定方向，不跟随屏幕进行旋转，参考代码如下，以下代码需在module.json5配置文件的requestPermissions标签中对[ohos.permission.CAMERA](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/permissions-for-all-user#ohospermissioncamera)相机权限进行[声明权限](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/declare-permissions)：

import { camera } from '@kit.CameraKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit';


@Entry
@Component
struct CameraExampleDemo {
  private xComponentCtl: XComponentController = new XComponentController();
  private xComponentSurfaceId: string = '';
  @State imageWidth: number = 1920;
  @State imageHeight: number = 1080;
  private cameraManager: camera.CameraManager | undefined = undefined;
  private cameras: Array<camera.CameraDevice> = \[\];
  private cameraInput: camera.CameraInput | undefined = undefined;
  private previewOutput: camera.PreviewOutput | undefined = undefined;
  private session: camera.VideoSession | undefined = undefined;
  private uiContext: UIContext = this.getUIContext();
  private context: Context | undefined = this.uiContext.getHostContext();
  private cameraPermission: Permissions = 'ohos.permission.CAMERA';
  @State isShow: boolean = false;
  private isLock: boolean = true;

  async requestPermissionsFn(): Promise<void> {
    let atManager = abilityAccessCtrl.createAtManager();
    if (this.context) {
      let res = await atManager.requestPermissionsFromUser(this.context, \[this.cameraPermission\]);
      for (let i = 0; i < res.permissions.length; i++) {
        if (this.cameraPermission.toString() === res.permissions\[i\] && res.authResults\[i\] === 0) {
          this.isShow = true;
        }
      }
    }
  }

  aboutToAppear(): void {
    this.requestPermissionsFn();
  }

  onPageShow(): void {
    console.info('onPageShow');
    if (this.xComponentSurfaceId !== '') {
      this.initCamera();
    }
  }

  onPageHide(): void {
    console.info('onPageHide');
    this.releaseCamera();
  }

  build() {
    Column() {
      if (this.isShow) {
        XComponent({
          id: 'componentId',
          type: XComponentType.SURFACE,
          controller: this.xComponentCtl
        })
          .onLoad(async () => {
            let surfaceRotation: SurfaceRotationOptions = { lock: this.isLock };
            this.xComponentCtl.setXComponentSurfaceRotation(surfaceRotation);
            this.xComponentSurfaceId = this.xComponentCtl.getXComponentSurfaceId(); _// 获取组件surfaceId。_
           _ // 初始化相机，组件实时渲染每帧预览流数据。_
            this.initCamera();
          })
          .width(this.uiContext.px2vp(this.imageWidth))
          .height(this.uiContext.px2vp(this.imageHeight));
      }
    }
    .justifyContent(FlexAlign.Center)
    .height('100%')
    .width('100%');
  }

 _ // 初始化相机。_
  async initCamera(): Promise<void> {
    console.info(\`initCamera previewOutput xComponentSurfaceId:${this.xComponentSurfaceId}\`);
    try {
    _  // 获取相机管理器实例。_
      this.cameraManager = camera.getCameraManager(this.context);
      if (!this.cameraManager) {
        console.error('initCamera getCameraManager');
      }
      _// 获取当前设备支持的相机device列表。_
      this.cameras = this.cameraManager.getSupportedCameras();
      if (!this.cameras) {
        console.error('initCamera getSupportedCameras');
      }
      _// 选择一个相机device，创建cameraInput输出对象。_
      this.cameraInput = this.cameraManager.createCameraInput(this.cameras\[0\]);
      if (!this.cameraInput) {
        console.error('initCamera createCameraInput');
      }
   _   // 打开相机。_
      await this.cameraInput.open().catch((err: BusinessError) => {
        console.error(\`initCamera open fail: ${err}\`);
      });

    _  // 获取相机device支持的profile。_
      let capability: camera.CameraOutputCapability =
        this.cameraManager.getSupportedOutputCapability(this.cameras\[0\], camera.SceneMode.NORMAL\_VIDEO);
      if (!capability) {
        console.error('initCamera getSupportedOutputCapability');
      }
      let minRatioDiff: number = 1;
      let surfaceRatio: number = this.imageWidth / this.imageHeight; _// 最接近16:9宽高比。_
      let previewProfile: camera.Profile = capability.previewProfiles\[0\];
    _  // 应用开发者根据实际业务需求选择一个支持的预览流previewProfile。_
     _ // 此处以选择CAMERA\_FORMAT\_YUV\_420\_SP（NV21）格式、满足限定条件条件分辨率的预览流previewProfile为例。_
      for (let index = 0; index < capability.previewProfiles.length; index++) {
        const tempProfile = capability.previewProfiles\[index\];
        let tempRatio = tempProfile.size.width >= tempProfile.size.height ?
          tempProfile.size.width / tempProfile.size.height : tempProfile.size.height / tempProfile.size.width;
        let currentRatio = Math.abs(tempRatio - surfaceRatio);
        if (currentRatio <= minRatioDiff && tempProfile.format === camera.CameraFormat.CAMERA\_FORMAT\_YUV\_420\_SP) {
          previewProfile = tempProfile;
          break;
        }
      }
      this.imageWidth = previewProfile.size.width; _// 更新xComponent组件的宽。_
      this.imageHeight = previewProfile.size.height; _// 更新xComponent组件的高。_
     _ // 使用xComponentSurfaceId创建预览。_
      this.previewOutput = this.cameraManager.createPreviewOutput(previewProfile, this.xComponentSurfaceId);

      if (!this.previewOutput) {
        console.error('initCamera createPreviewOutput');
      }
     _ // 创建录像模式相机会话。_
      this.session = this.cameraManager.createSession(camera.SceneMode.NORMAL\_VIDEO) as camera.VideoSession;
      if (!this.session) {
        console.error('initCamera createSession');
      }
     _ // 开始配置会话。_
      this.session.beginConfig();
     _ // 添加相机设备输入。_
      this.session.addInput(this.cameraInput);
     _ // 添加预览流输出。_
      this.session.addOutput(this.previewOutput);
     _ // 提交会话配置。_
      await this.session.commitConfig();
    _  // 开始启动已配置的输入输出流。_
      await this.session.start();

    } catch (error) {
     _ // 停止当前会话。_
      await this.session?.stop();
    _  // 释放相机输入流。_
      await this.cameraInput?.close();
     _ // 释放预览输出流。_
      await this.previewOutput?.release();
      _// 释放会话。_
      await this.session?.release();
      console.error(\`initCamera fail: ${error}\`);
    }
  }

 _ // 释放相机。_
  async releaseCamera(): Promise<void> {
    console.info('releaseCamera E');
    try {
    _  // 停止当前会话。_
      await this.session?.stop();
     _ // 释放相机输入流。_
      await this.cameraInput?.close();
    _  // 释放预览输出流。_
      await this.previewOutput?.release();
    _  // 释放会话。_
      await this.session?.release();
    } catch (error) {
      console.error(\`initCamera fail: ${error}\`);
    }
  }
}