好的,我想我已经弄清楚了。这个谜题有几个要素,我感谢@kcoppock提供的帮助,帮助我解决了其中一些问题。
首先,在确定选择哪种预览尺寸时,需要考虑方向。例如,来自ApiDemos
的CameraPreview
中的getOptimalPreviewSize()
由于他们的应用程序版本将方向锁定为横向,所以并不知道方向。如果您希望让方向浮动,则需要反转目标宽高比以匹配。因此,getOptimalPreviewSize()
中有:
double targetRatio=(double)width / height;
你还需要:
if (displayOrientation == 90 || displayOrientation == 270) {
targetRatio=(double)height / width;
}
其中displayOrientation
是一个0到360的值,我从大约100行一些非常丑陋的代码中确定了这个值,这就是为什么我正在将所有这些内容包装在一个可重用的组件中,很快我会发布它。该代码基于setDisplayOrientation()
JavaDocs和这个StackOverflow答案。
(顺便说一句,如果您在2013年7月1日之后阅读此内容,并且您在此答案中看不到链接,则请发表评论提醒我,因为我忘记了)
其次,在控制您正在使用的SurfaceView
/TextureView
的纵横比时,您需要考虑显示方向。来自ApiDemos
的CameraPreview
活动具有其自己的Preview
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: 我的CWAC-Camera库 的 v0.0.1 版本现已发布,包含上述代码。
setPreviewSize()
的高度/宽度,这是不起作用的(除非反转后的大小恰好是有效的预览大小)。然而,通过反转预览View
本身(例如,SurfaceView
)的高度/宽度,我离正确的纵横比更接近了一些。它还不够准确,但它不像上面展示的那样过分了。谢谢! - CommonsWare