Android Camera 相機簡單操做

在Android 通常拍照主要有兩種方式,一種是調用系統相機,拍照以後獲取路徑顯示。而另一種則是調用Camera 而後去拍照。java

Ok,那麼今天講的是後者.主要是本身編寫代碼去完成拍照功能。android

首先咱們須要建一個 CameraPreview 類 ,固然也須要繼承 SurfaceView 並實現 SurfaceHolder.Callback接口,app

那麼該類主要是用做與顯示拍照預覽的。ide

import java.io.IOException;
import java.util.List;

import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * 相機圖片預覽類
 * 
 * @author
 * 
 */
public class CameraPreview extends SurfaceView implements
		SurfaceHolder.Callback
{

	public SurfaceHolder mHolder;

	private Camera mCamera;

	Size mPreviewSize;

	List<Size> mSupportedPreviewSizes;

	public CameraPreview(Context context, AttributeSet attrs, int defStyle)
	{
		super(context, attrs, defStyle);
		init();
	}

	public CameraPreview(Context context, AttributeSet attrs)
	{
		super(context, attrs);
		init();
	}

	public CameraPreview(Context context)
	{
		super(context);
		init();
	}

	/**
	 * 初始化工做
	 * 
	 */
	private void init()
	{

		// Install a SurfaceHolder.Callback so we get notified when the
		// underlying surface is created and destroyed.
		mHolder = getHolder();
		mHolder.addCallback(this);
		// deprecated setting, but required on Android versions prior to 3.0
		mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

	}

	// 設置相機
	public void setCamera(Camera camera)
	{

		mCamera = camera;
		if (mCamera != null)
		{
			mSupportedPreviewSizes = mCamera.getParameters()
					.getSupportedPreviewSizes();
			requestLayout();
		}
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder)
	{
		// The Surface has been created, now tell the camera where to draw the
		// preview.
		try
		{
			if (null != mCamera)
			{
				mCamera.setPreviewDisplay(holder);
			}
		} catch (IOException e1)
		{
			e1.printStackTrace();

		}
		try
		{
			if (null != mCamera)
			{
				mCamera.startPreview();
			}
		} catch (Exception e)
		{
		}
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
	{

		// If your preview can change or rotate, take care of those events here.
		// Make sure to stop the preview before resizing or reformatting it.

		if (null == mHolder.getSurface())
		{
			// preview surface does not exist
			return;
		}

		// stop preview before making changes
		try
		{
			if (null != mCamera)
			{
				mCamera.stopPreview();
			}
		} catch (Exception e)
		{
			// ignore: tried to stop a non-existent preview
		}

		// set preview size and make any resize, rotate or
		// reformatting changes here

		if (null != mCamera)
		{
			Camera.Parameters parameters = mCamera.getParameters();
			parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);

			requestLayout();

			mCamera.setParameters(parameters);
			mCamera.setDisplayOrientation(90);

		}
		// 這裏能夠用來設置尺寸

		// start preview with new settings
		try
		{
			if (null != mCamera)
			{

				mCamera.setPreviewDisplay(mHolder);
				mCamera.startPreview();
			}

		} catch (Exception e)
		{
		}
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder)
	{

		if (null != mCamera)
		{
			mCamera.stopPreview();
		}

	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
	{
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);

		// We purposely disregard child measurements because act as a
		// wrapper to a SurfaceView that centers the camera preview instead
		// of stretching it.
		final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
		final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
		setMeasuredDimension(width, height);

		if (mSupportedPreviewSizes != null)
		{
			mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
		}
	}

	private Size getOptimalPreviewSize(List<Size> sizes, int w, int h)
	{
		final double ASPECT_TOLERANCE = 0.1;
		double targetRatio = (double) w / h;
		if (sizes == null)
			return null;

		Size optimalSize = null;
		double minDiff = Double.MAX_VALUE;

		int targetHeight = h;

		// Try to find an size match aspect ratio and size
		for (Size size : sizes)
		{
			double ratio = (double) size.width / size.height;
			if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
				continue;
			if (Math.abs(size.height - targetHeight) < minDiff)
			{
				optimalSize = size;
				minDiff = Math.abs(size.height - targetHeight);
			}
		}

		// Cannot find the one match the aspect ratio, ignore the requirement
		if (optimalSize == null)
		{
			minDiff = Double.MAX_VALUE;
			for (Size size : sizes)
			{
				if (Math.abs(size.height - targetHeight) < minDiff)
				{
					optimalSize = size;
					minDiff = Math.abs(size.height - targetHeight);
				}
			}
		}
		return optimalSize;
	}

}

完成該類以後,咱們就須要編寫如何打開相機,並如何拍照了。

首先你能夠本身定義一個佈局,而後搞上該類。但今天不寫佈局,直接用代碼生成。佈局

ok ,那麼咱們須要先定義一下須要用到的變量。ui

private Camera mCamera; // 相機

    int mDefaultCameraId; // 默認相機ID

    private CameraPreview mPreview; // 集成SurfaceView 的類

    int mScreenWidth, mScreenHeight; // 屏幕寬和高

    FrameLayout preview; // 佈局

    private File saveVideoFile; // 保存文件

而後咱們開始生成佈局文件,這裏固然須要在onCreate方法中完成

// 無標題欄的窗口
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

        // 選擇支持半透明模式,在有surfaceview的activity中使用。
        getWindow().setFormat(PixelFormat.TRANSLUCENT);

        // 獲得屏幕的大小
        WindowManager wManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        Display display = wManager.getDefaultDisplay();
        mScreenHeight = display.getHeight();
        mScreenWidth = display.getWidth();

        mPreview = new CameraPreview(this);

        preview = new FrameLayout(getApplicationContext());

        // 將相機預覽圖加入幀佈局裏面
        preview.addView(mPreview, 0);

        setContentView(preview);
        
        <pre style="background-color:#ffffff;color:#000000;font-family:'宋體';font-size:9.0pt;"><span style="background-color:#ffe4ff;">        mDefaultCameraId</span> = CameraUtils.<span style="font-style:italic;">getDefaultCameraId</span>();

 

ok,生成這些以後,遵守面向對象的理念,咱們將操做相機的方法進行封裝 CameraUtils 類

import android.hardware.Camera;
import android.view.SurfaceView;
import android.widget.FrameLayout;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created by on 16-2-29.
 */
public class CameraUtils {

    /**
     * 獲取默認的相機
     * @return
     */
    public static int getDefaultCameraId(){
        int defaultId = -1;

        // Find the total number of cameras available
        int mNumberOfCameras = Camera.getNumberOfCameras(); // 獲得攝像頭個數
        // Find the ID of the default camera
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        for (int i = 0; i < mNumberOfCameras; i++)
        {
            Camera.getCameraInfo(i, cameraInfo);
            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK)
            {
                defaultId = i;
            }
        }
        if (-1 == defaultId)
        {
            if (mNumberOfCameras > 0)
            {
                // 若是沒有後向攝像頭
                defaultId = 0;
            } else
            {
                //沒有攝像頭
                return -1;
                // 沒有攝像頭

            }
        }
        return defaultId;
    }

    /**
     * 打開相機
     * @param cameraId 鏡頭ID 0位前置 1爲後置
     * @param exception 錯誤信息, 若是打開錯誤 則賦值給他
     * @return 不爲NULL 則打開成功
     */
    public static Camera getCameraInstance(int cameraId,Exception exception)
    {
        Camera c = null;
        try
        {
            c = Camera.open(cameraId); // attempt to get a Camera instance
            if (cameraId == Camera.CameraInfo.CAMERA_FACING_BACK)
            {

                Camera.Parameters params = c.getParameters();
                params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); // 設置聚焦方式

                c.setParameters(params);
            }
        } catch (Exception e)
        {
            // Camera is not available (in use or does not exist)
            e.printStackTrace();
            exception = e;
            return null;
        }
        return c; // returns null if camera is unavailable
    }

    public static final int MEDIA_TYPE_IMAGE = 1;

    public static final int MEDIA_TYPE_VIDEO = 2;

    /**
     * 獲取輸出文件類型
     * @param type 1 Image 2爲VIDEO
     * @param saveFilePath 保存文件路徑 須要在尾加上/
     * @return File 類 錯誤則爲空
     */
    public static  File getOutputMediaFile(int type,String saveFilePath)
    {
        File mediaStorageDir = null;
        try
        {
            mediaStorageDir = new File(saveFilePath);

        } catch (Exception e)
        {
            e.printStackTrace();
        }

        // Create the storage directory if it does not exist
        if (!mediaStorageDir.exists())
        {
            if (!mediaStorageDir.mkdirs())
            {
                // 在SD卡上建立文件夾須要權限:
                // <uses-permission
                // android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
                return null;
            }
        }

        // Create a media file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
                .format(new Date());
        File mediaFile;
        if (type == MEDIA_TYPE_IMAGE)
        {
            mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
        } else if (type == MEDIA_TYPE_VIDEO)
        {
            mediaFile = new File(mediaStorageDir.getPath() + File.separator + "VID_" + timeStamp + ".mp4");
        } else
        {
            return null;
        }

        return mediaFile;
    }


    /**
     * 釋放相機
     * @param mCamera 相機
     * @throws Exception
     */
    public static void releaseCamera(Camera mCamera) throws Exception {

            if (mCamera != null)
            {
                mCamera.setPreviewCallback(null);
                mCamera.stopPreview();// 停掉原來攝像頭的預覽
                Camera.Parameters  p = mCamera.getParameters();
                if (p.getFlashMode().equals(Camera.Parameters.FLASH_MODE_TORCH))
                    p.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
                p.setZoom(0);
                mCamera.setParameters(p);

                mCamera.release();
                mCamera = null;
            }
    }


}

ok,那麼如今開始打開相機

mCamera = CameraUtils.getCameraInstance(mDefaultCameraId=0,mException);
        if(mCamera == null){
            Log.v(TAG,"open Camera Error");
          
            return ;
        }
        mPreview.setCamera(mCamera);
        mCamera.startPreview();

完成這步以後,大體上就能夠預覽相機了。那麼開始拍照、

寫一個內部類this

/**
     * 拍照
     */
    private Camera.PictureCallback mPicture = new Camera.PictureCallback()
    {

        @Override
        public void onPictureTaken(byte[] data, Camera camera)
        {

            File pictureFile = CameraUtils.getOutputMediaFile(CameraUtils.MEDIA_TYPE_IMAGE,saveFilePath);
            if (pictureFile == null)
            {
                return;
            }

            try
            {
                FileOutputStream fos = new FileOutputStream(pictureFile);
                fos.write(data);
                fos.close();
            } catch (FileNotFoundException e)
            {
                Log.d(TAG, e.getMessage());
            } catch (IOException e)
            {
                Log.d(TAG, e.getMessage());
            }
            // 拍照後從新開始預覽
            mCamera.stopPreview();
            mCamera.startPreview();
        }
    };

那麼拍照能夠直接調用方法

mCamera.takePicture(null, null, mPicture);
那麼到這裏就完成一個拍照功能的應用了。
相關文章
相關標籤/搜索