纵向模式下的相机setDisplayOrientation()打破纵横比

Com*_*are 15 android android-camera

我试图让相机预览在纵向模式下正常工作,其中活动本身可以正常改变方向(即,不被锁定到风景).

但是,使用setDisplayOrientation()严重打破了预览的行为.

这可以通过谷歌自己的ApiDemos来证明.第一个图像基于示例项目CameraPreviewandroid-17版本ApiDemos,其中我做的唯一更改是android:orientation="landscape"从清单中的此活动的条目中删除.下图是运行Android 4.2的Nexus 4显示屏上显示的内容的屏幕截图,相机指向一张8.5平方英寸的纸张:

Nexus 4 ApiDemos预览,纵向模式

该预览中不明显的是它旋转了90度.您在图像最右侧看到的袜子包裹的脚实际上位于正方形下方.

对此,至少对于横向模式,解决方案是使用setDisplayOrientation().但是,如果修改了Preview内部类的CameraPreviewmCamera.setDisplayOrientation(90);,你会得到这样的:

Nexus 4 ApiDemos预览,纵向模式,带setDisplayOrientation(90)

值得注意的是,广场不再是正方形.

它使用与SurfaceView以前相同的大小.我已经使用其他一些代码重现了这个场景ApiDemos,并且我TextureView在该代码中得到了相同的行为.

我简单地想到问题可能是getSupportedPreviewSizes()基于可能会返回不同的值setDisplayOrientation(),但快速测试表明情况并非如此.

任何人都知道如何setDisplayOrientation()在纵向模式下工作而不会破坏图像的宽高比推到预览中?

谢谢!

Com*_*are 15

好吧,我想我想出来了.众所周知的谜题有几个部分,我感谢@kcoppock帮助我解决其中一些问题的见解.

首先,在确定要选择的预览尺寸时,需要考虑方向.例如,getOptimalPreviewSize()from CameraPreviewof the ApiDemosis is is is not orientation,只是因为他们的应用版本的方向已锁定为横向.如果您希望方向浮动,则需要反转目标纵横比以匹配.那么,哪里getOptimalPreviewSize()有:

double targetRatio=(double)width / height;
Run Code Online (Sandbox Code Playgroud)

你还需要:

if (displayOrientation == 90 || displayOrientation == 270) {
  targetRatio=(double)height / width;
}
Run Code Online (Sandbox Code Playgroud)

其中displayOrientation是一个从0到360的值,我从大约100行的一些严重丑陋的代码中确定,这就是为什么我将所有这些包装在一个可重用的组件中,我将很快发布.该代码是基于setDisplayOrientation()JavaDoc中这个StackOverflow的答案.

(顺便说一句,如果您在2013年7月1日之后阅读此内容,并且您没有在该组件的答案中看到链接,请发表评论以提醒我,因为我忘了)

其次,在控制正在使用的SurfaceView/ 的宽高比时,需要考虑该显示方向TextureView.在CameraPreview从活动ApiDemos有其自身Preview ViewGroup处理该宽高比,在那里你需要扭转在肖像使用长宽比:

    if (displayOrientation == 90
        || displayOrientation == 270) {
      previewWidth=mPreviewSize.height;
      previewHeight=mPreviewSize.width;
    }
    else {
      previewWidth=mPreviewSize.width;
      previewHeight=mPreviewSize.height;
    }
Run Code Online (Sandbox Code Playgroud)

这里displayOrientation是相同的值(90270是人像和反向画像分别与注意,我没有尝试过得到相反的画像或反向景观的工作,所以有可能会需要更多的调整).

三-和一个,我觉得真气-你必须在调用之前启动预览setPictureSize()Camera.Parameters.否则,就好像图片的宽高比被应用于预览帧一样,搞砸了.

所以我以前的代码类似于以下内容:

Camera.Parameters parameters=camera.getParameters();
Camera.Size pictureSize=getHost().getPictureSize(parameters);

parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
parameters.setPictureSize(pictureSize.width, pictureSize.height);
parameters.setPictureFormat(ImageFormat.JPEG);

camera.setParameters(parameters);
camera.startPreview();
Run Code Online (Sandbox Code Playgroud)

那是错的.你真正需要的是:

Camera.Parameters parameters=camera.getParameters();
Camera.Size pictureSize=getHost().getPictureSize(parameters);

parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);

camera.setParameters(parameters);
camera.startPreview();

parameters=camera.getParameters();
parameters.setPictureSize(pictureSize.width, pictureSize.height);
parameters.setPictureFormat(ImageFormat.JPEG);
camera.setParameters(parameters);
Run Code Online (Sandbox Code Playgroud)

如果没有这种变化,即使在风景中,我也会得到拉伸的纵横比.这不是一个问题CameraPreviewApiDemos,因为他们不拍照,所以他们从来不叫setPictureSize().

但是,到目前为止,在Nexus 4上,我现在具有纵向和横向的纵横比,具有浮动方向(即,未锁定到横向).

如果我遇到其他设备所需的其他黑客,并且在发布时链接到我的CameraView/ CameraFragment组件,我会尽量记住修改这个问题.


更新#1

嗯,当然,它不可能通过这么简单.:-)

解决setPictureSize()纵横比搞砸问题的问题......直到你拍照.此时,预览会切换到错误的宽高比.

一种可能性是将图片限制为与预览具有相同(或非常接近)宽高比的图片,因此不存在打嗝.我不喜欢这个答案,因为用户应该能够获得相机提供的任何图片尺寸.

您可以通过以下方式限制损坏的范围:

  • 仅在拍摄Camera.Parameters之前更新图片尺寸等
  • 恢复到前拍照Camera.Parameters拍摄照片后,

在拍照时,这仍然呈现错误的宽高比.对于这个问题的长期解决方案 - 我认为 - 将在拍摄照片时暂时用静止图像(最后一个预览帧)替换相机预览.我最终会试试这个.


更新#2:我的CWAC-Camera库的 v0.0.1 现已可用,包含上述代码.


归档时间:

查看次数:

11614 次

最近记录:

10 年,7 月 前