Android Camera 相机简单操作

8 篇文章 0 订阅
4 篇文章 0 订阅

在Android 一般拍照主要有两种方式,一种是调用系统相机,拍照之后获取路径显示。而另外一种则是调用Camera 然后去拍照。

Ok,那么今天讲的是后者.主要是自己编写代码去完成拍照功能。

首先我们需要建一个 CameraPreview 类 ,当然也需要继承 SurfaceView 并实现 SurfaceHolder.Callback接口,

那么该类主要是用作与显示拍照预览的。

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 ,那么我们需要先定义一下需要用到的变量。

    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();

完成这步之后,大致上就可以预览相机了。那么开始拍照、

写一个内部类

 /**
     * 拍照
     */
    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);

那么到这里就完成一个拍照功能的应用了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值