您的位置:首页 > 移动开发 > Android开发

Android相机应用

2015-11-28 20:39 267 查看
Android相机应用
布局

功能实现

拍照

附录

Android相机应用

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

布局

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

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

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


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

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

[code]  <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,并且全屏显示。

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


1. 根据之前说的操作逻辑,我们首先实现触摸屏幕显示拍照按钮。

重写
onTouchEvent()
方法,在方法中,我们通过对实例化过的私有成员变量
layout
的设置,来显示布局中的RelativeLayout(button就位于这个相对布局中)

[code]@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卡读写的权限,这里也一并加上:

[code]<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()
方法来配置:

[code]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接口,完成未实现的方法:

[code]    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接口并完成未实现的方法:

[code]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

[code]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);
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: