android – 相机setDisplayOrientation()在纵向模式中断长宽比

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

虽然使用setDisplayOrientation()严重打破了预览的行为.

这可以由Google自己的ApiDemos来证明.第一个图像是基于ApiDemos示例项目的android-17版本的CameraPreview,其中唯一的更改是从该活动的清单中的条目中删除android:orientation =“landscape”.以下图片是运行Android 4.2的Nexus 4显示屏上显示的屏幕截图,相机指向8.5“平方英尺的纸张:

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

解决方案,至少对于横向模式,是使用setDisplayOrientation().但是,如果您将CameraPreview的Preview内部类修改为具有mCamera.setDisplayOrientation(90);则可以得到:

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

这使用与之前相同的SurfaceView大小.我已经在ApiDemos之外的一些其他代码再现了这种情况,并且我在该代码中与TextureView获得相同的行为.

我简单地想到,问题可能是getSupportedPreviewSizes()可能会返回基于setDisplayOrientation()的不同值,但是一个快速测试表明不是这样.

任何人都有任何想法如何使setDisplayOrientation()工作在纵向模式,而不会破坏图像的纵横比推到预览?

谢谢!

好的,我想我想出来了.有一些谚语的谜题,我感谢@kcoppock的帮助我解决了一些这样的见解.

首先,在确定要选择的预览大小时,您需要考虑方向.例如,ApiDemos的CameraPreview中的getOptimalPreviewSize()忽略了方向,只是因为它们的该应用程序的版本已锁定到横向.如果要让方向浮动,则需要将目标宽高比相反.那么getOptimalPreviewSize()有:

double targetRatio=(double)width / height;

你也需要:

if (displayOrientation == 90 || displayOrientation == 270) {
  targetRatio=(double)height / width;
}

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

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

其次,在控制您正在使用的SurfaceView / TextureView的宽高比时,您需要考虑到该显示方向.来自ApiDemos的CameraPreview活动具有自己的预览ViewGroup来处理宽高比,您需要将纵横比逆转为纵向使用:

    if (displayOrientation == 90
        || displayOrientation == 270) {
      previewWidth=mPreviewSize.height;
      previewHeight=mPreviewSize.width;
    }
    else {
      previewWidth=mPreviewSize.width;
      previewHeight=mPreviewSize.height;
    }

其中displayOrientation是相同的值(90和270分别是纵向和反向肖像,并注意到我没有尝试获得反向肖像或反向风景),因此可能需要更多的调整.

第三 – 一个我觉得很愤怒 – 你必须在Camera.Parameters上调用setPictureSize()之前开始预览.否则,就好像将图片的宽高比应用于预览框架,拧紧东西.

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

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();

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

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);

没有这种变化,我会得到一个拉伸的长宽比,即使在景观.对于ApiDemos的CameraPreview来说,这并不是一个问题,因为他们没有拍照,所以他们从来不会调用setPictureSize().

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

如果我遇到其他设备所需的其他黑客,还要链接到我的CameraView / CameraFragment组件,我会尝试记住修改这个问题.

更新#1

那么当然,这几乎不可能这么简单. 🙂

setPictureSize()拧紧长宽比的问题的修复工作…直到你拍照.此时,预览切换到错误的纵横比.

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

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

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

在拍摄照片的时刻,这仍然表现出错误的纵横比.这个长期的解决方案 – 我想 – 将是在拍摄照片时暂时用静止图像(最后一个预览框)替换相机预览.我会试试这个.

更新#2:现在可以使用my CWAC-Camera library的v0.0.1,并入上述代码.

http://stackoverflow.com/questions/17126633/camera-setdisplayorientation-in-portrait-mode-breaks-aspect-ratio

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:android – 相机setDisplayOrientation()在纵向模式中断长宽比