20

我试图创建一个简单的相机应用程序进行研究。我阅读了Android Camera 官方文档,然后开始编码。所以我做了一些步骤让它工作

1.在应用程序中添加了相机功能所需的权限。

2.将我的活动锁定为仅肖像模式。

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

3.添加了几个相机回调来让我的相机工作。

  • SurfaceHolder.Callback,
  • Camera.PreviewCallback
  • 自动对焦回调
  • 快门回调
  • RAW 图像数据的 PictureCallback
  • JPG 图像数据的 PictureCallback

4.在surfaceChanged方法中,我正在自定义相机设置。到目前为止,我几乎可以为所有安卓设备工作

  • LG
  • 香料
  • 三星
  • 宏达电
  • 微麦克斯
  • 索尼
  • 摩托罗拉
  • 谷歌 Nexus 系列。

后来我用 Android 版本 2.3.6 在三星 Galaxy ACE上进行了测试,发现相机显示预览被旋转到横向模式。

因此,在放置 log-cat/break 点之后,我知道下面的方法不适用于这个特定的模型

//This method is not working for Samsung Galaxy ACE
 camera.setDisplayOrientation(90); 
//or 
parameters.set("orientation", "portrait");
//or
parameters.setRotation(90);

注意: 我也在谷歌和 SO 上寻找了一堆解决方案,但到目前为止还没有得到任何运气

供您参考我的示例代码如下

@Override
    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
        Log.v(TAG, "surfaceChanged get called");

        if (previewing) {
            camera.stopPreview();
            previewing = false;
        }

        if (camera != null) {
            try {
                Camera.Parameters parameters = camera.getParameters();
                List<Size> sizes = parameters.getSupportedPictureSizes();

                Camera.Size result = null;
                for (int i = 0; i < sizes.size(); i++) {
                    result = (Size) sizes.get(i);
                    Log.i("PictureSize", "Supported Size. Width: "
                            + result.width + "height : " + result.height);

                    if (result.width == 640) {
                        parameters.setPreviewSize(result.width, result.height);// 640*480
                        parameters.setPictureSize(result.width, result.height);
                    } else {

                    }
                }


                //**************************************************************//

                /* 
                 * Here is the logic I have added to Manage Camera Display Orientation
                 *  It checks Current Orientation and SDK and then rotate display to make it Portrait view.
                 */
                int currentSDKVersion = android.os.Build.VERSION.SDK_INT;
                Log.d(TAG, "currentVersion " + currentSDKVersion);

                if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
                    if (currentSDKVersion != 7) {

                        camera.setDisplayOrientation(90);
                         parameters.setRotation(90);
                    } else {
                            parameters.setRotation(90);

                        /*
                         * params.set("orientation", "portrait");
                         * params.set("rotation",90);
                         */
                    }
                } else if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
                    if (currentSDKVersion != 7) {

                        camera.setDisplayOrientation(0);
                    } else {

                        parameters.set("orientation", "landscape");
                        parameters.set("rotation", 90);

                    }
                }


                //**************************************************************//

                camera.setParameters(parameters);
                camera.setPreviewDisplay(surfaceHolder);
                camera.startPreview();
                camera.autoFocus(myAutoFocusCallback);
                camera.setOneShotPreviewCallback(cameraPreviewCallback);
                previewing = true;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

我的相机活动(MainActivity.java)完整代码是:

public class MainActivity extends Activity implements SurfaceHolder.Callback,
        OnClickListener {

    public static final String TAG = "CameraActivity";
    private Context context = null;
    Camera camera = null;
    private SurfaceView surfaceView = null;
    private SurfaceHolder surfaceHolder = null;
    boolean previewing = false;
    private LayoutInflater controlInflater = null;
    private Button buttonTakePicture = null;
    //private TextView textViewResultInfo = null;

    @SuppressWarnings("deprecation")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Log.v(TAG, "onCreate get called");

        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        //textViewResultInfo = (TextView) findViewById(R.id.textViewResultInfo);
        context = this;

        getWindow().setFormat(PixelFormat.UNKNOWN);
        surfaceView = (SurfaceView) findViewById(R.id.surfaceview);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        controlInflater = LayoutInflater.from(getBaseContext());
        View viewControl = controlInflater.inflate(R.layout.control, null);
        LayoutParams layoutParamsControl = new LayoutParams(
                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
        this.addContentView(viewControl, layoutParamsControl);

        buttonTakePicture = (Button) findViewById(R.id.takepicture);
        buttonTakePicture.setOnClickListener(this);

    }

    @Override
    public void surfaceCreated(SurfaceHolder arg0) {

        Log.v(TAG, "surfaceCreated get called");
        camera = Camera.open();

        if (camera != null) {
            try {
                camera.setPreviewDisplay(surfaceHolder);
                camera.startPreview();
                previewing = true;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    @Override
    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
        Log.v(TAG, "surfaceChanged get called");

        if (previewing) {
            camera.stopPreview();
            previewing = false;
        }

        if (camera != null) {
            try {

                 //new MainActivity().setCameraDisplayOrientation();

                Camera.Parameters parameters = camera.getParameters();
                // List<String> focusModes =
                // parameters.getSupportedFocusModes();
                // if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO))
                // {
                // parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
                // }

                List<Size> sizes = parameters.getSupportedPictureSizes();

                Camera.Size result = null;
                for (int i = 0; i < sizes.size(); i++) {
                    result = (Size) sizes.get(i);
                    Log.i("PictureSize", "Supported Size. Width: "
                            + result.width + "height : " + result.height);

                    if (result.width == 640) {
                        parameters.setPreviewSize(result.width, result.height);// 640*480
                        parameters.setPictureSize(result.width, result.height);
                    } else {

                    }
                }


                //**************************************************************//

                Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
                int rotation = display.getRotation();
                Log.v(TAG, "Current Device Orientation is ="+rotation);

                /* 
                 * Here is the logic I have added to Manage Camera Display Orientation
                 *  It checks Current Orientation and SDK and then rotate display to make it Portrait view.
                 */
                int currentSDKVersion = android.os.Build.VERSION.SDK_INT;
                Log.d(TAG, "currentVersion " + currentSDKVersion);

                if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
                    if (currentSDKVersion != 7) {
                        Log.i(TAG, "ORIENTATION_PORTRAIT +SDK is: " + currentSDKVersion
                                + "rotate 90");
                        camera.setDisplayOrientation(90);
                         parameters.setRotation(90);
                    } else {
                        Log.i(TAG, "ORIENTATION_PORTRAIT +SDK is: " + currentSDKVersion
                                + "rotate 90");
                        parameters.setRotation(90);

                        /*
                         * params.set("orientation", "portrait");
                         * params.set("rotation",90);
                         */
                    }
                } else if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
                    if (currentSDKVersion != 7) {
                        Log.i(TAG, "ORIENTATION_LANDSCAPE +SDK is: " + currentSDKVersion
                                + "rotate 90");

                        camera.setDisplayOrientation(0);
                    } else {

                        Log.i(TAG, "ORIENTATION_LANDSCAPE +SDK is: " + currentSDKVersion
                                + "rotate 90");

                        parameters.set("orientation", "landscape");
                        parameters.set("rotation", 90);

                    }
                }


                //**************************************************************//


                camera.setParameters(parameters);
                camera.setPreviewDisplay(surfaceHolder);
                camera.startPreview();
                camera.autoFocus(myAutoFocusCallback);
                camera.setOneShotPreviewCallback(cameraPreviewCallback);
                previewing = true;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder arg0) {
        Log.v(TAG, "surfaceDestroyed get called");
        camera.stopPreview();
        camera.release();
        camera = null;
        previewing = false;

    }


    public void setCameraDisplayOrientation() 
    {        
        Log.v(TAG, "setCameraDisplayOrientation get called");

         if (camera == null)
         {
             Log.d(TAG,"setCameraDisplayOrientation - camera null");
             return;             
         }

         Camera.CameraInfo info = new Camera.CameraInfo();
         Camera.getCameraInfo(1, info);

         WindowManager winManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         int rotation = winManager.getDefaultDisplay().getRotation();

         int degrees = 0;

         switch (rotation) 
         {
             case Surface.ROTATION_0: degrees = 0; break;
             case Surface.ROTATION_90: degrees = 90; break;
             case Surface.ROTATION_180: degrees = 180; break;
             case Surface.ROTATION_270: degrees = 270; break;
         }

         int result;
         if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) 
         {
             result = (info.orientation + degrees) % 360;
             result = (360 - result) % 360;  // compensate the mirror
         } else {  // back-facing
             result = (info.orientation - degrees + 360) % 360;
         }
         camera.setDisplayOrientation(result);
    }


    @Override
    public void onClick(View v) {
        Log.v(TAG, "onClick get called");

        if (v == buttonTakePicture) {
            camera.takePicture(myShutterCallback, myPictureCallback_RAW,
                    myPictureCallback_JPG);
        }

    }

    private Camera.PreviewCallback cameraPreviewCallback = new Camera.PreviewCallback() {
        @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
            Log.i(TAG, "onPreviewFrame size=" + data.length);
        }
    };

    AutoFocusCallback myAutoFocusCallback = new AutoFocusCallback() {

        @Override
        public void onAutoFocus(boolean arg0, Camera arg1) {
            Log.v(TAG, "onAutoFocus get called");
            buttonTakePicture.setEnabled(true);
        }
    };

    ShutterCallback myShutterCallback = new ShutterCallback() {

        @Override
        public void onShutter() {
            Log.v(TAG, "onShutter get called");
        }
    };

    PictureCallback myPictureCallback_RAW = new PictureCallback() {

        @Override
        public void onPictureTaken(byte[] arg0, Camera arg1) {
            Log.v(TAG, "onPictureTaken-RAW get called");

        }
    };

    public static Bitmap RotateBitmap(Bitmap source, float angle) {
        Matrix matrix = new Matrix();
        matrix.postRotate(angle);
        return Bitmap.createBitmap(source, 0, 0, source.getWidth(),
                source.getHeight(), matrix, true);
    }

    PictureCallback myPictureCallback_JPG = new PictureCallback() {

        @Override
        public void onPictureTaken(byte[] arg0, Camera arg1) {
            Bitmap rawImage = BitmapFactory.decodeByteArray(arg0, 0,
                    arg0.length);

            if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
                Log.v(TAG, "#####  ORIENTATION_PORTRAIT   ####");

                rawImage = MainActivity.RotateBitmap(rawImage, 90);

                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                rawImage.compress(Bitmap.CompressFormat.JPEG, 100, stream);
                arg0 = stream.toByteArray();

            } else if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
                Log.v(TAG, "#####   ORIENTATION_LANDSCAPE  #####");

            }

            Intent intent = new Intent(MainActivity.this, ResultActivity.class);
            intent.putExtra("picture", arg0);
            startActivity(intent);

            Log.v(TAG, "onPictureTaken-JPG get called");

        }
    };

    /**
     * Get the size in bitmap.
     * 
     * @param bitmap
     * @return size in bytes
     */
    @TargetApi(12)
    public static int getBitmapSize(Bitmap bitmap) {
        if (MainActivity.hasHoneycombMR1()) {
            return bitmap.getByteCount();
        }
        // Pre HC-MR1
        return bitmap.getRowBytes() * bitmap.getHeight();
    }

    public static boolean hasHoneycombMR1() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1;
    }

}

编辑:我在开发者论坛上发表了评论,但没有回复。

请!!有人对这个问题有任何想法。

我真的很感激任何建议。

4

3 回答 3

12

当运行 2.2.1 的原始 Galaxy Tab 遇到类似问题时,我可以通过执行以下操作来解决它:

Camera.Parameters parameters = camera.getParameters();
parameters.set("orientation", "portrait");
parameters.setRotation(90);
camera.setParameters(parameters);

但是,看起来您可能已经尝试过这种确切的组合,因为您在上面有相同(但已注释掉)的代码。但是,按照您现在拥有代码的方式,Ace 将绕过您拥有注释代码的位置,因为它是 API 级别 (10)。在此块内专门尝试一下:

if (currentSDKVersion != 7) { }

请让我知道它是否有效。谢谢!

于 2013-10-08T20:00:45.667 回答
0

我也在寻找解决方案几个小时。它真的很疯狂。我的解决方案是在横向模式下(在我的纵向应用程序中)使用相机预览,并屏蔽掉我不需要的预览部分。我通过用一些视图覆盖全屏预览的上下部分来做到这一点。当然,您必须裁剪从相机中获取的照片,这会导致分辨率较低。对于我的应用程序来说,这不是问题。

我现在对我的解决方案非常满意——用户没有看到任何区别;

于 2013-11-13T10:52:45.093 回答
0

我通过编写一些主要改编自 ZXing 项目的代码来处理相机:http ://code.google.com/p/zxing/

你可以尝试使用这些。如果您尝试使用它,我建议您通过这个stackoverflow 问题的解决方案

这可能不是您问题的完美解决方案,但我已经解决了这个问题并决定使用 Zxing。

于 2013-12-12T11:34:05.567 回答