Android自定義照相機 預覽拍照 切換前后置攝像頭

異常:java.lang.RuntimeException: setParameters failed
Android調用camera錯誤setParameters failed深層解析
真機測試報錯ERROR/AndroidRuntime: java.lang.RuntimeException: setParameters failed解決辦法
Android關閉自定義相機拍照聲音
android 自定義相機Camera2

自定義相機自動對焦處理

Android提供了Camera來控制拍照,步驟如下:
(1)調用Camera的open()方法打開相機。
(2)調用Camera的getParameters()獲取拍照參數,該方法返回一個Cmera.Parameters對象。
(3)調用Camera.Parameters對象對照相的參數進行設置。
(4)調用Camera的setParameters(),并將Camera.Parameters對象作為參數傳入,這樣就可以對拍照進行參數控制,Android2.3.3以后不用設置。
(5)調用Camerade的startPreview()的方法開始預覽取景,在之前需要調用Camera的setPreviewDisplay(SurfaceHolder holder)設置使用哪個SurfaceView來顯示取得的圖片。
(6)調用Camera的takePicture()方法進行拍照。
(7)程序結束時,要調用Camera的stopPreview()方法停止預覽,并且通過Camera.release()來釋放資源。

需要賦予Camera的權限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.CAMERA"/>

具體代碼:

package com.lyj.camera;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PictureCallback;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.ImageView;

public class MyCameraActivity extends Activity implements SurfaceHolder.Callback {
    private ImageView back, position;//返回和切換前后置攝像頭
    private SurfaceView surface;
    private ImageButton shutter;//快門
    private SurfaceHolder holder;
    private Camera camera;//聲明相機
    private String filepath = "";//照片保存路徑
    private int cameraPosition = 1;//0代表前置攝像頭,1代表后置攝像頭

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_NO_TITLE);//沒有標題
        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//設置全屏
        this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);//拍照過程屏幕一直處于高亮
        //設置手機屏幕朝向,一共有7種
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
        //SCREEN_ORIENTATION_BEHIND: 繼承Activity堆棧中當前Activity下面的那個Activity的方向
        //SCREEN_ORIENTATION_LANDSCAPE: 橫屏(風景照) ,顯示時寬度大于高度 
        //SCREEN_ORIENTATION_PORTRAIT: 豎屏 (肖像照) , 顯示時高度大于寬度 
        //SCREEN_ORIENTATION_SENSOR  由重力感應器來決定屏幕的朝向,它取決于用戶如何持有設備,當設備被旋轉時方向會隨之在橫屏與豎屏之間變化
        //SCREEN_ORIENTATION_NOSENSOR: 忽略物理感應器——即顯示方向與物理感應器無關,不管用戶如何旋轉設備顯示方向都不會隨著改變("unspecified"設置除外)
        //SCREEN_ORIENTATION_UNSPECIFIED: 未指定,此為默認值,由Android系統自己選擇適當的方向,選擇策略視具體設備的配置情況而定,因此不同的設備會有不同的方向選擇
        //SCREEN_ORIENTATION_USER: 用戶當前的首選方向

        setContentView(R.layout.main);

        back = (ImageView) findViewById(R.id.camera_back);
        position = (ImageView) findViewById(R.id.camera_position);
        surface = (SurfaceView) findViewById(R.id.camera_surface);
        shutter = (ImageButton) findViewById(R.id.camera_shutter);
        holder = surface.getHolder();//獲得句柄
        holder.addCallback(this);//添加回調
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//surfaceview不維護自己的緩沖區,等待屏幕渲染引擎將內容推送到用戶面前

        //設置監聽
        back.setOnClickListener(listener);
        position.setOnClickListener(listener);
        shutter.setOnClickListener(listener);
    }

    //響應點擊事件
    OnClickListener listener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            switch (v.getId()) {
            case R.id.camera_back:
                //返回
                MyCameraActivity.this.finish();
                break;

            case R.id.camera_position:
                //切換前后攝像頭
                int cameraCount = 0;
                CameraInfo cameraInfo = new CameraInfo();
                cameraCount = Camera.getNumberOfCameras();//得到攝像頭的個數

                for(int i = 0; i < cameraCount; i   ) {
                    Camera.getCameraInfo(i, cameraInfo);//得到每一個攝像頭的信息
                    if(cameraPosition == 1) {
                        //現在是后置,變更為前置
                        if(cameraInfo.facing  == Camera.CameraInfo.CAMERA_FACING_FRONT) {//代表攝像頭的方位,CAMERA_FACING_FRONT前置      CAMERA_FACING_BACK后置  
                            camera.stopPreview();//停掉原來攝像頭的預覽
                            camera.release();//釋放資源
                            camera = null;//取消原來攝像頭
                            camera = Camera.open(i);//打開當前選中的攝像頭
                            try {
                                camera.setPreviewDisplay(holder);//通過surfaceview顯示取景畫面
                            } catch (IOException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                            camera.startPreview();//開始預覽
                            cameraPosition = 0;
                            break;
                        }
                    } else {
                        //現在是前置, 變更為后置
                        if(cameraInfo.facing  == Camera.CameraInfo.CAMERA_FACING_BACK) {//代表攝像頭的方位,CAMERA_FACING_FRONT前置      CAMERA_FACING_BACK后置  
                            camera.stopPreview();//停掉原來攝像頭的預覽
                            camera.release();//釋放資源
                            camera = null;//取消原來攝像頭
                            camera = Camera.open(i);//打開當前選中的攝像頭
                            try {
                                camera.setPreviewDisplay(holder);//通過surfaceview顯示取景畫面
                            } catch (IOException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                            camera.startPreview();//開始預覽
                            cameraPosition = 1;
                            break;
                        }
                    }

                }
                break;

            case R.id.camera_shutter:
                //快門
                camera.autoFocus(new AutoFocusCallback() {//自動對焦
                    @Override
                    public void onAutoFocus(boolean success, Camera camera) {
                        // TODO Auto-generated method stub
                        if(success) {
                            //設置參數,并拍照
                            Parameters params = camera.getParameters();
                            params.setPictureFormat(PixelFormat.JPEG);//圖片格式
                            params.setPreviewSize(800, 480);//圖片大小
                            camera.setParameters(params);//將參數設置到我的camera
                            camera.takePicture(null, null, jpeg);//將拍攝到的照片給自定義的對象
                        }
                    }
                });
                break;
            }
        }
    };

    /*surfaceHolder他是系統提供的一個用來設置surfaceView的一個對象,而它通過surfaceView.getHolder()這個方法來獲得。
     Camera提供一個setPreviewDisplay(SurfaceHolder)的方法來連接*/

    //SurfaceHolder.Callback,這是個holder用來顯示surfaceView 數據的接口,他必須實現以下3個方法
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // TODO Auto-generated method stub

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        //當surfaceview創建時開啟相機
        if(camera == null) {
            camera = Camera.open();
            try {
                camera.setPreviewDisplay(holder);//通過surfaceview顯示取景畫面
                camera.startPreview();//開始預覽
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        //當surfaceview關閉時,關閉預覽并釋放資源
        camera.stopPreview();
        camera.release();
        camera = null;
        holder = null;
        surface = null;
    }

    //創建jpeg圖片回調數據對象
    PictureCallback jpeg = new PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            // TODO Auto-generated method stub
            try {
                Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
                //自定義文件保存路徑  以拍攝時間區分命名
                filepath = "/sdcard/Messages/MyPictures/"   new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())   ".jpg";
                File file = new File(filepath);
                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);//將圖片壓縮的流里面
                bos.flush();// 刷新此緩沖區的輸出流
                bos.close();// 關閉此輸出流并釋放與此流有關的所有系統資源
                camera.stopPreview();//關閉預覽 處理數據
                camera.startPreview();//數據處理完后繼續開始預覽
                bitmap.recycle();//回收bitmap空間
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    };
}

轉參

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容