Android自己创建一个相机应用

   我们需要使用到的是两个比较重要的类:Camera(注意这里的Camera类是在android.hardware.Camera这个包下的)和Camera.Parameters 这两个类的对象分别对应于一个摄像头硬件和摄像头参数集。同时我们还需要使用到两个比较重要的接口:SurfaceHolder.Callback和PictureCallback 这两个类可以实现预览画面和拍照的方法。

    首先我们先创建一个简单的布局文件

<strong><span style="font-size:18px;"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".CameraActivity">

    <SurfaceView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/camera_surfaceView"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:id="@+id/camera_btn_change"
        android:text="切换摄像头"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:id="@+id/camera_btn_photo"
        android:text="拍照"/>

</RelativeLayout></span></strong>


   同时我们也要像系统申请摄像头的权限和操作SD卡的权限:

    <strong><span style="font-family:FangSong_GB2312;font-size:18px;"><uses-permission android:name="android.permission.CAMERA"></uses-permission>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission></span></strong>

         并且我们需要让Activity固定竖屏(实际需要看个人,一般来说固定Activity的方向比较好):

<activity
            android:name=".CameraActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    接下来是我们的JAVA代码我们需要实现SurfaceHolder.Callback和PictureCallback两个类的接口,同时实现对应的几个方法:

    SurfcaceHolder.Callback的三个需要实现的方法:

    surfacCreated方法会在SurfaceView显示的时候系统回调 

<span style="font-family:FangSong_GB2312;font-size:18px;"><strong>@Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        try {
            //将摄像头取景给到一个SurfaceHolder对象 SurfaceHolder对象会在Surface显示取景
            camera.setPreviewDisplay(surfaceHolder);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //这里是旋转摄像头,因为摄像头都是横置(有些机型也可能是竖立的,根据情况来调整)
        camera.setDisplayOrientation(90);
        //设置摄像头参数
        camera.setParameters(parameters);
        //开始显示预览
        camera.startPreview();
    }</strong></span>

    surfacChanged方法会在SurfaceView形状改变的时候调用  

@Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
        if (surfaceHolder.getSurface()==null){
            return;
        }
        //先停止预览
        camera.stopPreview();
        //将取景设置到SurfaceHolder对象
        try {
            camera.setPreviewDisplay(surfaceHolder);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //旋转摄像头
        camera.setDisplayOrientation(90);
        //设置摄像头参数
        camera.setParameters(parameters);
        //开始预览
        camera.startPreview();
    }
     surfaceDestroyed方法会在surfView消失的时候调用     

@Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        if (camera!=null){
            camera.stopPreview();
            //如果进入这个Activity始终是从onCreat方法进入的则可以释放
            //如果是从onRestart进入的则不能释放,因为在surfaceCreated方法里面并没有实例化Camera对象
            //camera.release();
        }
    }

PictureCallback需要实现的方法,这个方法会在我们执行Camera的takePicture()方法的时候,系统来调用。我们可以在这里获取到摄像头拍下的相片数据

  我们可以对数据进行一些简单的处理,这里主要就是保存相片

@Override
    public void onPictureTaken(byte[] bytes, Camera camera) {
        //通过BitmapFactory的decodeByteArray()方法将获取到的相片数据给一个Bitmap对象赋值
        Bitmap bitmap = BitmapFactory.decodeByteArray(bytes,0,bytes.length);
        //创建一个Matrix对象 用于旋转照片 因为初始的照片的方向是和人观察的相反的
        Matrix matrix = new Matrix();
        //如果是后置摄像头 则顺时针旋转90度 反之逆时针旋转90度
        if (cameraCount%cameraId==0){
            matrix.setRotate(90);
        }else if (cameraCount%cameraId==1){
            matrix.setRotate(-90);
        }
        //通过Bitmap的createBitmap方法来旋转图片
        bitmap = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);
        //定义一个输出缓存流
        BufferedOutputStream bos = null;
        //在SD卡创建一个存放照片的目录
        File file = new File("mnt/sdcard/mycamera/picture/");
        file.mkdirs();
        //为照片取一个默认的名字
        String fileName = DateFormat.format("yyyy-MM-dd-hh:mm:ss", Calendar.getInstance())+".jpg";
        //照片的绝对路径
        String path = "mnt/sdcard/mycamera/picture"+fileName;
        try {
            //为照片创建一个缓存输出流
            bos = new BufferedOutputStream(new FileOutputStream(path));
            //将bitmap的数据写入bos里
            bitmap.compress(Bitmap.CompressFormat.JPEG,100,bos);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            if (bos!=null){
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
 现在我们需要在Acitvity的onCreate方法里面执行一些初始化的操作:

  

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //取消标题栏和设置全屏
        this.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);
        setContentView(R.layout.layout_camera);
        btn_photo = (Button) findViewById(R.id.camera_btn_photo);
        btn_change = (Button) findViewById(R.id.camera_btn_change);
        cameraView  = (SurfaceView) findViewById(R.id.camera_surfaceView);

        //打开默认摄像头
        camera = Camera.open();
        //获取摄像头初始参数集
        parameters = camera.getParameters();
        //获取摄像头个数
        cameraId = Camera.getNumberOfCameras();

        //为按钮设置监听
        btn_photo.setOnClickListener(this);
        btn_change.setOnClickListener(this);

        //通过SurfaceView对象获取一个SurfaceHolder对象 并且用SurfaceHolder对象来调用addCallback方法
        cameraView.getHolder().addCallback(this);

    }
   启动拍照的方法  

camera.takePicture(null,null,this);



完整代码:

package wpf.app.mycamera;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.text.format.DateFormat;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;


public class CameraActivity extends ActionBarActivity implements View.OnClickListener, SurfaceHolder.Callback, Camera.PictureCallback {

    SurfaceView cameraView;
    Button btn_photo;
    Button btn_change;

    int cameraCount;
    int cameraId;

    Camera camera;
    Camera.Parameters parameters;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //取消标题栏和设置全屏
        this.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);
        setContentView(R.layout.layout_camera);
        btn_photo = (Button) findViewById(R.id.camera_btn_photo);
        btn_change = (Button) findViewById(R.id.camera_btn_change);
        cameraView  = (SurfaceView) findViewById(R.id.camera_surfaceView);

        //打开默认摄像头
        camera = Camera.open();
        //获取摄像头初始参数集
        parameters = camera.getParameters();
        //获取摄像头个数
        cameraId = Camera.getNumberOfCameras();

        //为按钮设置监听
        btn_photo.setOnClickListener(this);
        btn_change.setOnClickListener(this);

        //通过SurfaceView对象获取一个SurfaceHolder对象 并且用SurfaceHolder对象来调用addCallback方法
        cameraView.getHolder().addCallback(this);

    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        try {
            //将摄像头取景给到一个SurfaceHolder对象 SurfaceHolder对象会在Surface显示取景
            camera.setPreviewDisplay(surfaceHolder);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //这里是旋转摄像头,因为摄像头都是横置(有些机型也可能是竖立的,根据情况来调整)
        camera.setDisplayOrientation(90);
        //设置摄像头参数
        camera.setParameters(parameters);
        //开始显示预览
        camera.startPreview();
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
        if (surfaceHolder.getSurface() == null) {
            return;
        }
        //先停止预览
        camera.stopPreview();
        //将取景设置到SurfaceHolder对象
        try {
            camera.setPreviewDisplay(surfaceHolder);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //旋转摄像头
        camera.setDisplayOrientation(90);
        //设置摄像头参数
        camera.setParameters(parameters);
        //开始预览
        camera.startPreview();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        if (camera != null) {
            camera.stopPreview();
            //如果进入这个Activity始终是从onCreat方法进入的则可以释放
            //如果是从onRestart进入的则不能释放,因为在surfaceCreated方法里面并没有实例化Camera对象
            //camera.release();
        }
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.camera_btn_change:
                if (camera!=null){
                    camera.stopPreview();
                    camera.release();
                }
                cameraCount++;
                camera = Camera.open(cameraCount%cameraId);
                try {
                    camera.setPreviewDisplay(cameraView.getHolder());
                    camera.setDisplayOrientation(90);
                    camera.setParameters(parameters);
                    camera.startPreview();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            case R.id.camera_btn_photo:
                //自动对焦
                camera.autoFocus(null);
                camera.takePicture(null,null,this);
        }
    }

    @Override
    public void onPictureTaken(byte[] bytes, Camera camera) {
        //通过BitmapFactory的decodeByteArray()方法将获取到的相片数据给一个Bitmap对象赋值
        Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        //创建一个Matrix对象 用于旋转照片 因为初始的照片的方向是和人观察的相反的
        Matrix matrix = new Matrix();
        //如果是后置摄像头 则顺时针旋转90度 反之逆时针旋转90度
        if (cameraCount % cameraId == 0) {
            matrix.setRotate(90);
        } else if (cameraCount % cameraId == 1) {
            matrix.setRotate(-90);
        }
        //通过Bitmap的createBitmap方法来旋转图片
        bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        //定义一个输出缓存流
        BufferedOutputStream bos = null;
        //在SD卡创建一个存放照片的目录
        File file = new File("mnt/sdcard/mycamera/picture/");
        file.mkdirs();
        //为照片取一个默认的名字
        String fileName = DateFormat.format("yyyy-MM-dd-hh:mm:ss", Calendar.getInstance()) + ".jpg";
        //照片的绝对路径
        String path = "mnt/sdcard/mycamera/picture" + fileName;
        try {
            //为照片创建一个缓存输出流
            bos = new BufferedOutputStream(new FileOutputStream(path));
            //将bitmap的数据写入bos里
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}




  

     



















  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值