相机setDisplayOrientation()在人像模式打破宽高比 [英] Camera setDisplayOrientation() in Portrait Mode Breaks Aspect Ratio

查看:574
本文介绍了相机setDisplayOrientation()在人像模式打破宽高比的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图让相机previews在人像模式,活动本身是可以正常改变方向(即不被锁定为横向)正常工作。

I am trying to get camera previews to work properly in portrait mode, where the activity itself is allowed to change orientation normally (i.e., not be locked to landscape).

使用 setDisplayOrientation()严重破坏了previews的行为,虽然。

The use of setDisplayOrientation() seriously breaks the behavior of the previews, though.

这可以通过谷歌自己的ApiDemos证明。第一个图像是根据相机preVIEW 从的的android-17 ApiDemos 示例项目,在那里我做了唯一的变化是删除安卓方向=从清单本次活动的条目风景。下图是显示一台Nexus 4的显示屏上,运行Android 4.2的截图,用相机对准一张8.5方:

This can be demonstrated by Google's own ApiDemos. The first image is based on the CameraPreview from the android-17 edition of the ApiDemos sample project, where the only change I made was to remove android:orientation="landscape" from this activity's entry in the manifest. The following image is a screenshot of what appears on the display of a Nexus 4, running Android 4.2, with the camera pointed at a 8.5" square of paper:

这是不从preVIEW明显的是,它被旋转90度。您最右边的图像中看到的袜子,包脚实际上是正方形下面。

What is not obvious from that preview is that it is rotated 90 degrees. The sock-clad feet that you see on the far right of the image were actually below the square.

对此的解决方案,至少在横向模式,就是用 setDisplayOrientation()。但是,如果修改 preVIEW 内部类的相机preVIEW mCamera.setDisplayOrientation(90); ,你会得到这样的:

The solution for this, at least for landscape mode, is to use setDisplayOrientation(). But, if you modify the Preview inner class of CameraPreview to have mCamera.setDisplayOrientation(90);, you get this:

值得注意的是,广场上已不再是正方形。

Notably, the square is no longer square.

这和以前一样SurfaceView 尺寸使用相同的。我纷纷转载此方案与其他一些code, ApiDemos 之外,我也得到与 TextureView 在code。

This uses the same SurfaceView size as before. I have reproduced this scenario with some other code, outside of ApiDemos, and I get the same behavior with TextureView in that code.

我想简要地,这个问题可能是 getSupported previewSizes()可能返回根据不同的值setDisplayOrientation(),但快速测试表明,这是并非如此。

I thought briefly that the issue might be that getSupportedPreviewSizes() might return different values based upon setDisplayOrientation(), but a quick test suggests that this is not the case.

任何人有任何想法如何获得 setDisplayOrientation()在纵向模式下工作,不破坏该图像的长宽比被推到preVIEW?

Anyone have any idea how to get setDisplayOrientation() to work in portrait mode without wrecking the aspect ratio of the imagery pushed over to the preview?

谢谢!

推荐答案

好了,我想我想通了这一点。有几件众所周知的难题,我感谢@kcoppock的,帮助我解决了一些这方面的见解。

OK, I think that I figured this out. There were a few pieces to the proverbial puzzle, and I thank @kcoppock for the insight that helped me solve some of this.

首先,你需要的时候决定哪些preVIEW大小来选择走的方向考虑。例如, getOptimal previewSize()相机preVIEW ApiDemos 是浑然不觉的方向,只是因为他们的应用程序的版本已锁定为横向的方向。如果你希望让方向浮动,你需要扭转的目标纵横比相匹配。所以,这里的 getOptimal previewSize()有:

First, you need to take the orientation into account when determining what preview size to choose. For example, the getOptimalPreviewSize() from the CameraPreview of ApiDemos is oblivious to orientation, simply because their version of that app has the orientation locked to landscape. If you wish to let the orientation float, you need to reverse the target aspect ratio to match. So, where getOptimalPreviewSize() has:

double targetRatio=(double)width / height;

您还需要:

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

其中, displayOrientation 是一个值从0到360,那我从大约100行的一些确定的认真的丑陋code,这就是为什么我包装了这一切在我将很快发布一个可重用的组件。这code是根据<一href="http://developer.android.com/reference/android/hardware/Camera.html#setDisplayOrientation%28int%29">the setDisplayOrientation()的JavaDoc 和这个计算器回答

where displayOrientation is a value from 0 to 360, that I am determining from about 100 lines of some seriously ugly code, which is why I am wrapping all of this up in a reusable component that I'll publish shortly. That code is based on the setDisplayOrientation() JavaDocs and this StackOverflow answer.

(顺便说一句,如果你是1日后阅读本7月2013,你没有看到这个问题的答案组件链接,发表评论提醒我,因为我忘了)

(BTW, if you are reading this after 1 July 2013, and you don't see a link in this answer to that component, post a comment to remind me, as I forgot)

二,你控制的长宽比时需要采取的显示方向考虑到 SurfaceView / TextureView 您正在使用。从相机preVIEW 活动 ApiDemos 都有自己的 preVIEW 的ViewGroup 处理纵横比,在那里你需要扭转的纵横比在人像模式:

Second, you need to take that display orientation into account when controlling the aspect ratio of the SurfaceView/TextureView that you are using. The CameraPreview activity from ApiDemos has its own Preview ViewGroup that handles the aspect ratio, and there you need to reverse the aspect ratio for use in portrait:

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

其中, displayOrientation 是相同的值( 90 270 是纵向和分别反向画像,并注意我没有尝试过得到相反的画像或反向景观的工作,所以有可能会需要更多的调整)。

where displayOrientation is that same value (90 and 270 being portrait and reverse-portrait respectively, and note that I haven't tried getting reverse-portrait or reverse-landscape to work, so there may be more tweaking required).

三 - 一,我觉得真气 - 你必须在调用 setPictureSize()摄像机前开始preVIEW。参数。否则,它是因为如果所述的图像的纵横比的施加到preVIEW帧,螺纹连接东西。

Third -- and one that I find infuriating -- you must start the preview before calling setPictureSize() on the Camera.Parameters. Otherwise, it's as if the aspect ratio of the picture is applied to the preview frames, screwing things up.

所以,我曾经有code类似以下内容:

So I used to have code resembling the following:

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

和这是错误的。你真正需要的是:

and that's wrong. What you really need is:

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 相机preVIEW 一个问题,因为他们不拍照,等他们从来没有所谓的 setPictureSize()

Without that change, I'd get a stretched aspect ratio, even in landscape. This wasn't a problem for CameraPreview of ApiDemos, as they were not taking pictures, and so they never called setPictureSize().

但是,到目前为止,关于一个的Nexus 4,我现在有纵向和横向方长宽比,带有浮动取向(即不锁定到横向)。

But, so far, on a Nexus 4, I now have square aspect ratios for portrait and landscape, with a floating orientation (i.e., not locked to landscape).

我会努力记住,如果我碰上其它设备所需的其他黑客修改了这个问题,再加上链接到我的 CameraView / CameraFragment 成分被释放,当他们。

I'll try to remember to amend this question if I run into other hacks required by other devices, plus to link to my CameraView/CameraFragment components when they are released.

更新#1

嗯,当然,它不可能通过的的这个简单的。 : - )

Well, of course, it couldn't possibly by nearly this simple. :-)

有关,其中 setPictureSize()螺丝了长宽比的作品...,直到你拍摄照片的问题的解决方法。在这一点上,preVIEW切换到错误的高宽比。

The fix for the problem where setPictureSize() screws up the aspect ratio works... until you take a picture. At that point, the preview switches to the wrong aspect ratio.

一种可能是将图片限制到那些具有相同的(或非常接近)宽高比到preVIEW,所以打嗝不存在。我不喜欢这个答案,因为用户应该能够得到任何画面尺寸的相机提供。

One possibility would be to limit pictures to ones with the same (or very close) aspect ratio to the preview, so the hiccup does not exist. I don't like that answer, as the user should be able to get whatever picture size the camera offers.

您可以限制损失的范围:

You can limit the scope of the damage by:

  • 仅在更新画面大小,等等。 Camera.Parameters 之前拍照
  • 恢复为pre-拍照 Camera.Parameters 拍摄照片后
  • Only updating the picture size, etc. of the Camera.Parameters just before taking the picture
  • Reverting to the pre-picture-taking Camera.Parameters after taking the picture

这还是presents在瞬间错误的宽高比,而图片是上当受骗。这样做的长远的解决办法 - 我认为 - 会暂时取代相机preVIEW与静止图像(最后preVIEW帧),而图片是上当受骗。我会尝试这最终。

This still presents the wrong aspect ratio during the moments while the picture is being taken. The long-term solution for this -- I think -- will be to temporarily replace the camera preview with a still image (the last preview frame) while the picture is being taken. I'll try this eventually.

更新#2 我CWAC-相机库现已推出,结合上述code。

UPDATE #2: v0.0.1 of my CWAC-Camera library is now available, incorporating the aforementioned code.

这篇关于相机setDisplayOrientation()在人像模式打破宽高比的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆