捕获图像而不使用意图,在不同设备上输出不同

16

我的要求既不是显示相机预览,也不是使用相机意图进行图片捕捉。

因此,我找到了一种对我的第一个测试设备(Galaxy tab 7")有效的方法。

我的CaptureImage函数如下:

private void CaptureImage() {
        int FrontCameraFound = getCameraID();
        if (FrontCameraFound != -1) {
            mCamera = Camera.open(FrontCameraFound);

            parameters = mCamera.getParameters();

            mCamera.setParameters(parameters);
            mCamera.startPreview();

            Camera.PictureCallback mCall = new Camera.PictureCallback() {
                @Override
                public void onPictureTaken(byte[] data, Camera camera) {

                    bmp = BitmapFactory.decodeByteArray(data, 0, data.length);

                    // set bitmap tp image view just to check 
                    // if image capture proper, testing purpose
                    iv_image.setImageBitmap(bmp);

                    mCamera.stopPreview();
                    mCamera.release();
                    mCamera = null;
                }
            };
            mCamera.takePicture(null, null, mCall);
        }
    }

并且 getCameraID 函数如下所示

private int getCameraID() {
    Camera.CameraInfo cameraInfo = new Camera.CameraInfo();

    for (int camIdx = 0; camIdx < Camera.getNumberOfCameras(); camIdx++) {
        Camera.getCameraInfo(camIdx, cameraInfo);
        // for capture image from back camera
        // If want to capture from front 
        // then change it to CAMERA_FACING_FRONT
        if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
            try {
                return camIdx;
            } catch (RuntimeException e) {

            }
        }
    }
    return -1;
}

我现在遇到的困难是在不同的设备上成功运行上述代码。

  • Samsung Galaxy S+ (2.3.6):前置摄像头始终返回绿色图像,但后置摄像头的编码工作正常。
  • Samsung Galaxy Nexus (4.1):编码对于前置和后置摄像头都不能正常工作,并且会显示“takePicture”失败。
  • LG Optimus Net (2.3.4):只有后置摄像头并且工作正常。
  • Samsung Galaxy Tab 7 " (2.3.3):两个摄像头都可以正常工作。
  • Motorola Xoom (3.1):两个摄像头都可以正常工作。

三星Galaxy Nexus的Logcat:

09-21 09:37:42.125: E/AndroidRuntime(4647): Caused by: java.lang.RuntimeException: takePicture failed
09-21 09:37:42.125: E/AndroidRuntime(4647):     at android.hardware.Camera.native_takePicture(Native Method)
09-21 09:37:42.125: E/AndroidRuntime(4647):     at android.hardware.Camera.takePicture(Camera.java:1061)
09-21 09:37:42.125: E/AndroidRuntime(4647):     at android.hardware.Camera.takePicture(Camera.java:1006)
09-21 09:37:42.125: E/AndroidRuntime(4647):     at fortyonepost.com.pwop.TakePictureDemoActivity.CaptureImage(TakePictureDemoActivity.java:63)
09-21 09:37:42.125: E/AndroidRuntime(4647):     at fortyonepost.com.pwop.TakePictureDemoActivity.onCreate(TakePictureDemoActivity.java:36)
09-21 09:37:42.125: E/AndroidRuntime(4647):     at android.app.Activity.performCreate(Activity.java:5008)
09-21 09:37:42.125: E/AndroidRuntime(4647):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
09-21 09:37:42.125: E/AndroidRuntime(4647):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)

无法为每个设备检查代码,我只在5个设备上测试了我的代码,其中2个设备出现了问题,那么有没有标准的方法可以从相机中获取图像而不使用意图和预览。

请注意,我在清单中包含了<uses-permission android:name="android.permission.CAMERA"/>,并将最低SDK版本设置为9

更新: 在4.1 Nexus Galaxy上,Camera.java类中第1061行的takePicture Failed,这里是类链接,给我提供了信息:Camera.java中的native_takePicture(msgType)函数抛出了该异常。


我想在不让用户知道的情况下从相机中捕获图像,并且必须兼容所有API级别为9+的设备,正如我在问题中提到的,在某些设备上它可以正常工作,但对于某些设备来说却不能按照问题中所述工作。 - rajpara
在Galaxy Nexus上的logcat中,takePicture()方法显示是从onCreate()而不是您的CaptureImage()方法调用的。这正确吗? - Joe
抱歉,之前我将CaptureImage函数命名为surfaceChanged。我已经编辑了logcat。 - rajpara
不显示相机预览和相机意图,你如何拍摄照片?是的,“您想捕捉手机屏幕的图像吗?” - Paresh Mayani
不,我不想捕捉手机屏幕,正如我上面提到的,代码在Xoom、Galaxy Tab、LG Net和HTC Wildfire上运行良好,而且不会向用户显示预览或使用相机意图,但是对于两个设备,我遇到了问题。 - rajpara
3个回答

3

经过多次搜索,我发现相机预览是必要的,我想知道即使代码有问题,它在某些设备上为什么能够正常工作。

任何情况下的解决方案是,

我们需要在 surface view 上保持相机预览,并且我们可以将该 surface view 隐藏在任何其他视图后面。我在 framelayout 中使用 surface view(我知道这已经被弃用了),并在其上面放置 image view,对于 surface view,我只使用了 80 * 80 dp 的 surface view,因为小的 surface view,如 30 * 30 dp,无法工作并且会再次出错。


3
在Android设备中处理相机是一个很大的问题,不同的设备(甚至是同一设备上的不同Android版本)可能会有不同的行为。基本上,你正在与设备上的某些恶魔进程交互,它们彼此之间也不同。
我没有所有问题的解决方案,但以下是我的研究结果:
- 并非所有分辨率都能正常工作,即使它们在相机参数中被广告。您必须在设置相机时进行测试以防出现问题。 - 预览数据通过mmapped内存区域传递给您。 - NV21格式始终提供并应为默认值,但我建议查询相机设置。当您打开相机时,它可能具有其他应用程序使用相机时的某些设置。(没有任何地方说明相机会在打开时重置为默认值)
我已经为JavaOCR项目开发了一些相机管理工具,并且在大多数设备上都可以使用。请随意将其用作灵感来源。

http://sourceforge.net/p/javaocr/code/240/tree/trunk/demos/camera-utils/src/main/java/net/sf/javaocr/demos/android/utils/camera/CameraManager.java


一个非常愚蠢的问题:是否必须通过表面或表面纹理显示预览?因为没有预览,我无法在4.1中捕获图像。顺便说一句,感谢分享代码,我会参考它的。 - rajpara
1
文档说明需要传递完全配置的SurfaceView并启动预览才能拍照。但是,没有要求SurfaceView在前面可见。请参阅:http://developer.android.com/reference/android/hardware/Camera.html - Konstantin Pribluda
那么你的意思是,如果我们将表面保持不可见,这个问题就会得到解决,对吗? - rajpara
我不能保证这个方法一定能解决你的问题。但请记住,decodeBitmap() 方法需要压缩的位图数据,而 pictureCallback() 方法不一定会提供适当的压缩格式。你需要检查(或调整)相机配置以匹配这些格式并正确解码它。 - Konstantin Pribluda
我在从字节中获取位图方面没有遇到问题,而且我尝试将其设置为不可见,但仍然没有运气。 - rajpara
你的第一条评论帮助我找到了解决方案,我使用FrameLayout将Surface隐藏在ImageView后面,然后使用camera.setPreviewDisplay(SurfaceHolder),camera.startPreview()和camera.takePicture捕获图像,唯一的缺点是我们需要布局可见性。 - rajpara

1

您需要使用Camera.setOneShotPreviewCallback方法,然后处理图像。

尝试使用YuvImage并在将其传递给bitmapfactory之前进行压缩,如下所示:

YuvImage yuvimage = new YuvImage(byteArr, ImageFormat.NV21, width, height, null);
    Rect rect = new Rect(0, 0, width, height);
    ByteArrayOutputStream outstr = new ByteArrayOutputStream();
    yuvimage.compressToJpeg(rect, 100, outstr);
    Bitmap bm = BitmapFactory.decodeByteArray(outstr.toByteArray(), 0, outstr.size());

编辑:

您必须使用一个SurfaceView,但是这个SurfaceView可以被隐藏在另一个视图下面,因此在屏幕上不可见,但仍然存在并处于活动状态。


谢谢Tomas的回答,但我的主要问题是当调用takePicture函数时,它立即失败,因此onPictureTaken没有被调用。 - rajpara
尝试使用相机对象的setOneShotPreviewCallback(previewCallback)方法,而不是takePicture。 - tomas
但是如果没有预览,如何执行预览回调函数? - rajpara
正如Konstantin Pribluda答案中所述的评论,您必须拥有一个SurfaceView,并且它不能设置为不可见,但是您可以使用一个小的(1X1像素)SurfaceView并将另一个视图放在其上方,结果是对用户不可见的表面,我想这就是您想要的。 - tomas

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