Android相机应用

Android相机应用

Android应用可以调用系统相机和相册模块,学会使用相机会在特定的应用中有帮助,比如我最近的项目中用到二维码扫描就跟这个有关。


布局

这里用到的一个关键性的布局控件叫做<Surface View> <Surface View />现在我们要求达到的效果是,将camera采集到输出到SurfaceView控件上,当我们触摸屏幕的时候,将显示拍照Button。

1. 这里我们先设置放置Button父元素RelativeLayout的android:visibility属性为gone

<RelativeLayout
        android:id="@+id/buttonLayout"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:visibility="gone" >

我们必须要为RelativeLayout设置一个ID,方面我们在之后触摸事件后修改其属性。

2. 在RelativeLayout中设置Button的属性,主要是设置位置和onClick事件。

  <Button
            android:id="@+id/btnTakePic"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:gravity="center"
            android:onClick="TakePicture"
            android:text="@string/btnTakePic" />

至此,布局基本完成。


功能实现

在实现功能之前,我们希望打开相机之后,相机采集的数据回显到屏幕能够全屏显示,也就意味着没有屏幕最上方的TITLE显示。这样,需要我们在onCreate()方法中,加载布局文件之前先干掉title,并且全屏显示。

// 显示界面之前修改窗口属性
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);

1. 根据之前说的操作逻辑,我们首先实现触摸屏幕显示拍照按钮。
重写onTouchEvent()方法,在方法中,我们通过对实例化过的私有成员变量layout的设置,来显示布局中的RelativeLayout(button就位于这个相对布局中)

@Override
    public boolean onTouchEvent(MotionEvent event) {
        if(event.getAction()==MotionEvent.ACTION_DOWN){
            layout.setVisibility(ViewGroup.VISIBLE);//0x00000000
            return true;
        }
        return super.onTouchEvent(event);
    }

2. 把摄像头采集的画面输出到屏幕上。
编码之前千万不要忘记添加相机使用权限,之后估计还会用到SD卡读写的权限,这里也一并加上:

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

现在我们开始实现采集->显示这部分代码。首先通过找到SurfaceView控件并实例化,通过getHolder()方法来配置:

surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceView.getHolder().setFixedSize(176, 144);
surfaceView.getHolder().setKeepScreenOn(true);
//设置回调函数,当SurfaceView被创建的时候调用。
surfaceView.getHolder().addCallback(new SurfaceCallback());

addCallback()方法中需要一个对象,这里创建内部类实现Callback接口,完成未实现的方法:

    private final class SurfaceCallback implements Callback{
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            try{
            camera=Camera.open();//打开摄像头
            /*也可以使用默认参数
            Camera.Parameters parameters=camera.getParameters();
            parameters.setPreviewSize(1920,1080);
            parameters.setPreviewFrameRate(15);
            parameters.setPictureSize(1024, 768);
            parameters.setJpegQuality(100);
            camera.setParameters(parameters);
            */
            //采集的图像回显是斜的,在StackOverFlow上面看到的方法修正,但是好像并没有什么暖用
            Camera.Parameters params = camera.getParameters();
            //params.set("orientation", "portrait");
            //params.set("rotation",270);
            //下述才是正解
            camera.setDisplayOrientation(90);//旋转90度
            camera.setParameters(params);
            camera.setPreviewDisplay(holder);//采集->SurfaceView
            camera.startPreview();//开始预览
            }catch (Exception e){
                e.printStackTrace();
            }
            //Log.i("zhangxiao",parameters.flatten());
        }
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height) {
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            if(camera!=null){
            //销毁camera
                camera.release();
                camera=null;
            }
        }
    }

至此,完成了应用实现打开camera把采集的视频流回显到屏幕上的功能。


拍照

拍照功能的实现就简单多了,我们设置Button的onClick事件,当点击按钮时完成拍照,并将快照保存到SD卡的根目录中。事实上,我们使用camera.takePicture()即可完成拍照,这里面需要我们给定3个回调对象,分别是:

  • 快门事件的回调
  • 获取原始数据的回调
  • 获取编码后数据的回调

这里我们想要在SD卡中存储*.jpg文件,所以前两项给null,对于第三项,我们编写内部类实现PictureCallback接口并完成未实现的方法:

private final class JpegCallback implements PictureCallback{
        /* 拍照回调
         * @see android.hardware.Camera.PictureCallback#onPictureTaken(byte[], android.hardware.Camera)
         */
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
        //打开文件
            File jpgFile = new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis()+".jpg");
            try {
                //创建文件输出流
                FileOutputStream outStream =new FileOutputStream(jpgFile);
                //写文件
                outStream.write(data);
                outStream.close();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
    }

附录

com.example.takepicture.MainActivity.java

public class MainActivity extends Activity {
    private View layout;
    private Camera camera;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 显示界面之前修改窗口属性
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_main);
        layout=(View)this.findViewById(R.id.buttonLayout);
        SurfaceView surfaceView=(SurfaceView)this.findViewById(R.id.surfaceView);
        surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        surfaceView.getHolder().setFixedSize(176, 144);
        surfaceView.getHolder().setKeepScreenOn(true);
        surfaceView.getHolder().addCallback(new SurfaceCallback());
    }
    //TakePicture
    public void TakePicture(View v){
        if(camera!=null){
            //快门回调,    原始数据,      压缩数据
            camera.takePicture(null, null, new JpegCallback());
        }
    }
    private final class JpegCallback implements PictureCallback{
        /* 拍照回调
         * @see android.hardware.Camera.PictureCallback#onPictureTaken(byte[], android.hardware.Camera)
         */
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            File jpgFile = new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis()+".jpg");
            try {
                FileOutputStream outStream =new FileOutputStream(jpgFile);
                outStream.write(data);
                outStream.close();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    private final class SurfaceCallback implements Callback{
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            try{
            camera=Camera.open();//打开摄像头
            /*
            Camera.Parameters parameters=camera.getParameters();
            parameters.setPreviewSize(1920,1080);
            parameters.setPreviewFrameRate(15);
            parameters.setPictureSize(1024, 768);
            parameters.setJpegQuality(100);
            camera.setParameters(parameters);
            */
            Camera.Parameters params = camera.getParameters();
            //params.set("orientation", "portrait");
            //params.set("rotation",270);
            camera.setDisplayOrientation(90);//旋转90度
            camera.setParameters(params);
            camera.setPreviewDisplay(holder);

            camera.startPreview();
            }catch (Exception e){
                e.printStackTrace();
            }
            //Log.i("zhangxiao",parameters.flatten());
            //捕获的预览画面的大小

        }
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height) {
        }
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            if(camera!=null){
                camera.release();
                camera=null;
            }
        }
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if(event.getAction()==MotionEvent.ACTION_DOWN){
            layout.setVisibility(ViewGroup.VISIBLE);//0x00000000
            return true;
        }
        return super.onTouchEvent(event);
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值