Android自定義照相機(jī) 預(yù)覽拍照 切換前后置攝像頭

異常:java.lang.RuntimeException: setParameters failed
Android調(diào)用camera錯(cuò)誤setParameters failed深層解析
真機(jī)測(cè)試報(bào)錯(cuò)ERROR/AndroidRuntime: java.lang.RuntimeException: setParameters failed解決辦法
Android關(guān)閉自定義相機(jī)拍照聲音
android 自定義相機(jī)Camera2

自定義相機(jī)自動(dòng)對(duì)焦處理

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

需要賦予Camera的權(quán)限:

<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;//聲明相機(jī)
    private String filepath = "";//照片保存路徑
    private int cameraPosition = 1;//0代表前置攝像頭,1代表后置攝像頭

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

        requestWindowFeature(Window.FEATURE_NO_TITLE);//沒(méi)有標(biāo)題
        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//設(shè)置全屏
        this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);//拍照過(guò)程屏幕一直處于高亮
        //設(shè)置手機(jī)屏幕朝向,一共有7種
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
        //SCREEN_ORIENTATION_BEHIND: 繼承Activity堆棧中當(dāng)前Activity下面的那個(gè)Activity的方向
        //SCREEN_ORIENTATION_LANDSCAPE: 橫屏(風(fēng)景照) ,顯示時(shí)寬度大于高度 
        //SCREEN_ORIENTATION_PORTRAIT: 豎屏 (肖像照) , 顯示時(shí)高度大于寬度 
        //SCREEN_ORIENTATION_SENSOR  由重力感應(yīng)器來(lái)決定屏幕的朝向,它取決于用戶如何持有設(shè)備,當(dāng)設(shè)備被旋轉(zhuǎn)時(shí)方向會(huì)隨之在橫屏與豎屏之間變化
        //SCREEN_ORIENTATION_NOSENSOR: 忽略物理感應(yīng)器——即顯示方向與物理感應(yīng)器無(wú)關(guān),不管用戶如何旋轉(zhuǎn)設(shè)備顯示方向都不會(huì)隨著改變("unspecified"設(shè)置除外)
        //SCREEN_ORIENTATION_UNSPECIFIED: 未指定,此為默認(rèn)值,由Android系統(tǒng)自己選擇適當(dāng)?shù)姆较颍x擇策略視具體設(shè)備的配置情況而定,因此不同的設(shè)備會(huì)有不同的方向選擇
        //SCREEN_ORIENTATION_USER: 用戶當(dāng)前的首選方向

        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);//添加回調(diào)
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//surfaceview不維護(hù)自己的緩沖區(qū),等待屏幕渲染引擎將內(nèi)容推送到用戶面前

        //設(shè)置監(jiān)聽(tīng)
        back.setOnClickListener(listener);
        position.setOnClickListener(listener);
        shutter.setOnClickListener(listener);
    }

    //響應(yīng)點(diǎn)擊事件
    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();//得到攝像頭的個(gè)數(shù)

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

                }
                break;

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

    /*surfaceHolder他是系統(tǒng)提供的一個(gè)用來(lái)設(shè)置surfaceView的一個(gè)對(duì)象,而它通過(guò)surfaceView.getHolder()這個(gè)方法來(lái)獲得。
     Camera提供一個(gè)setPreviewDisplay(SurfaceHolder)的方法來(lái)連接*/

    //SurfaceHolder.Callback,這是個(gè)holder用來(lái)顯示surfaceView 數(shù)據(jù)的接口,他必須實(shí)現(xiàn)以下3個(gè)方法
    @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
        //當(dāng)surfaceview創(chuàng)建時(shí)開啟相機(jī)
        if(camera == null) {
            camera = Camera.open();
            try {
                camera.setPreviewDisplay(holder);//通過(guò)surfaceview顯示取景畫面
                camera.startPreview();//開始預(yù)覽
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

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

    //創(chuàng)建jpeg圖片回調(diào)數(shù)據(jù)對(duì)象
    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);
                //自定義文件保存路徑  以拍攝時(shí)間區(qū)分命名
                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();// 刷新此緩沖區(qū)的輸出流
                bos.close();// 關(guān)閉此輸出流并釋放與此流有關(guān)的所有系統(tǒng)資源
                camera.stopPreview();//關(guān)閉預(yù)覽 處理數(shù)據(jù)
                camera.startPreview();//數(shù)據(jù)處理完后繼續(xù)開始預(yù)覽
                bitmap.recycle();//回收bitmap空間
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    };
}

轉(zhuǎn)參

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,217評(píng)論 25 708
  • public classCamera.Parametersextends Objectjava.lang.Obje...
    冉冉升起的小太陽(yáng)閱讀 11,201評(píng)論 0 7
  • Android中開發(fā)相機(jī)的兩種方式Android系統(tǒng)提供了兩種使用手機(jī)相機(jī)資源實(shí)現(xiàn)拍攝功能的方法,一種是直接通過(guò)I...
    開發(fā)者也閱讀 3,125評(píng)論 0 14
  • 上一篇介紹了如何使用系統(tǒng)相機(jī)簡(jiǎn)單、快速的進(jìn)行拍照,本篇將介紹如何使用框架提供的API直接控制攝像機(jī)硬件。 你還在為...
    Xiao_Mai閱讀 7,395評(píng)論 4 18
  • 圣山 · 凈土 在我們的母親河長(zhǎng)江的源頭金沙江畔,海拔五千米的山腰,有一座古老的寺廟——古達(dá)拉寺,四周群山圍繞,此...
    摩尼寶閱讀 2,445評(píng)論 0 0

友情鏈接更多精彩內(nèi)容