如何在竖屏模式下旋转相机预览以拍摄横向照片?

4
我看到很多人想拍摄肖像照片时,建议他们将相机旋转90度。然而,无论我尝试什么,实际“旋转”的只是相机拍摄的图像,但它保留了宽高比例,因此,如果SurfaceView很窄而高,则图片不会失真。
我的目标是在3x4布局中拍摄一个未扭曲的4x3照片。它会非常窄,但我的目的是将预览视图旋转-90度,同时保持相机的正常纵横比。事实上,所有我尝试的方法都导致图片被压缩,如果我想将照片放在我的纵向布局中。
我开始怀疑我需要为预览应用一个矩阵,将其旋转-90度,但我不确定如何去做,或者那是否是正确的方法。希望能得到一些建议。
编辑:为了清楚起见,以下是Java文档的相关摘录:setPreviewSize(),“如果显示方向设置为0或180,预览大小应设置为480x320。如果显示方向设置为90或270,则预览大小应设置为320x480。”
这完全没有解决你想以纵向模式持有设备,但是希望相机预览出现在小的横向窗口中的情况(这正是我想要实现的)。
谢谢您。
2个回答

3
如果您使用SurfaceView来显示相机预览输出,并且希望确保预览在横向或纵向不会变形,那么您必须确保SurfaceView的宽高比与相机预览大小的宽高比相匹配。SurfaceView将简单地缩放预览以适应其内部,因此如果它的大小为500x500而您的预览大小为640x480,则预览将在垂直方向上被拉伸。
从概念上讲,最简单的方法是通过使用LayoutParamssetLayoutParams更新SurfaceView的布局为固定大小的布局,手动设置SurfaceView的宽度和高度。这种方法的问题在于,对于不同的屏幕尺寸,它可能会很脆弱,因为您需要弄清楚您真正想要的像素大小,并且对于Android上的直接跨设备布局,您真正想要考虑的是dp而不是像素。但是对于测试,您可以强制使SurfaceView具有测试设备屏幕的宽度,并将高度设置为
surface height = preview height / preview width * surface width

更好的方法是创建一个继承自SurfaceView的新类,在View的onMeasure方法中进行必要的纵横比调整。详细解释很长,但请查看Android开发者网站上的自定义组件文档以获取详细信息。但是大致上,您需要设置宽度/高度值,使其始终具有与配置的相机预览大小相同的纵横比。
一旦您拥有了正确大小的surfaceView,通常还需要使用setDisplayOrientation旋转摄像头预览输出;计算方向的数学可能会令人困惑,因此请使用上面文档链接提供的代码示例来解决问题。
基本上,世界有一个坐标系,相机传感器有另一个(固定在设备上),UI系统有第三个(固定在当前方向),而这三个可能相对于彼此改变。虽然正确的预览方向不取决于设备相对于世界的位置,但相机拍摄的图片的方向却是如此(由setRotation设置)。

这是一个很好的解释,我终于能够拍摄不会变形的照片了,但无论我尝试什么,预览仍然是扭曲的。如果您有一个实际旋转预览90度的代码示例,以便设置为纵向的Activity可以显示适当的照片预览,那将非常感激...我已经苦苦思索了4年(断断续续)。 - Yevgeny Simkin
假设您仍然指的是实时相机预览,而不是捕获照片的缩略图 - 在简短的说明中对Android的布局系统进行概述相当困难。但是,可以通过调用setDisplayOrientation来开始,上面链接的文档中有示例代码,可用于计算所需的旋转量。这至少可以让您获得正确的方向。 - Eddy Talvala
设置显示方向并不能解决问题。问题在于预览在被定向之前就已经被测量,因此它总是以相反的纵横比例显示(这意味着如果图像将成为4:3,则显示为3:4(即使它仍然被收集为4:3),因此会变形。 - Yevgeny Simkin
就像我所说的,这是必要的,但本身并不足够。 您知道在onResume或配置更改时,SurfaceView需要哪种纵横比以匹配当前的UI方向。因此,您需要调整其布局参数以进行匹配。这里有一个FixedAspectSurfaceView作为相机2 API中一个相机演示的一部分:https://github.com/googlesamples/android-HdrViewfinder/blob/master/Application/src/main/java/com/example/android/hdrviewfinder/FixedAspectSurfaceView.java 它提供了一个基本类来进行非拉伸预览,但仍需要在方向更改时进行纵横比更改。 - Eddy Talvala

-6

我的建议是,

在Android中不要过于关注布局,因为那非常困难。如果你想实现它,你必须阅读Android的开源代码,并在其中进行更改。

所以,我建议你使用Canvas(导入Graphics包)并利用这些类。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接