zoukankan      html  css  js  c++  java
  • CameraAPI中的 自定义照相功能

    前几天的项目需要使用CameraAPI自己定义照相机,之前用过的二维码也要自己写底层代码,于是总结一下使用CameraAPI的几点事项。现在由于JDK7.0及其以上版本的官方文档已经不再推荐使用camera包而是camera2包,但这次还是先讲camera的使用,至于camera2等以后再讲。

    首先是添加照相机权限,在清单文件中必须添加摄像头硬件权限和使用功能,其中功能可以根据项目需求选择性放入。

     1     <uses-permission android:name="android.permission.CAMERA"/>
     2     <!--使用摄像头硬件功能-->
     3     <uses-feature android:name="android.hardware.camera"/>
     4     <!--自动对焦功能-->
     5     <uses-feature android:name="android.hardware.camera.autofocus"/>
     6     <!--闪光灯功能-->
     7     <uses-feature android:name="android.hardware.camera.flash"/>
     8     <!--前置摄像头-->
     9     <uses-feature android:name="android.hardware.camera.front"/>

    关于权限和对应的功能可以参考文章 http://www.cnblogs.com/BobGo/articles/5646751.html;

    我在项目中需要两个功能,一是在显示摄像头的SurfaceView上添加一层ImageView,可以在ImageView上绘制不同的遮罩层;还有一个功能是摄像头拍摄照片之后显示及保存图片。

    第一是摄像头简单的使用,在这里可能会遇到在SurfaceView中摄像头的预览出现变形问题,下面会提到解决措施:

    1         SurfaceHolder surfaceHolder = surfaceView.getHolder();
    2         surfaceHolder.addCallback(this);
    3         surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    在当前类中实现SurfaceHolder.Callback 接口,重写三个方法 surfaceCreated(), surfaceChanged(), surfaceDestroy(),这三个方法就是SurfaceView对应的生命周期;

    surfaceCreated()中执行Camera.open()返回一个Camera对象,打开摄像头硬件,在surfaceDestroy()中,Camera对象调用release()释放摄像头;在surfaceChanged()中,设置摄像头参数,其中getBestSize()是确定手机摄像头硬件可以使用的最合适大小,这个算法是官方提供的。我在之前不采用这个算法而直接设置大小,导致在测试机运行时SurfaceView显示的图片出现变形。

     1 @Override
     2     public void surfaceCreated(SurfaceHolder holder) {
     3         camera = Camera.open();
     4     }
     5 
     6     @Override
     7     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
     8         //已经获得Surface的width和height,设置Camera的参数
     9         Camera.Parameters parameters = camera.getParameters();
    10         Camera.Size size=getBestSize(parameters.getSupportedPreviewSizes());
    11         int w=size.width;
    12         int h=size.height;
    13         parameters.setPreviewSize(w, h);
    14         parameters.setPictureSize(w, h);
    15 //        List<Camera.Size> vSizeList = parameters.getSupportedPictureSizes();
    16 //        for (int num = 0; num < vSizeList.size(); num++) {
    17 //            Camera.Size vSize = vSizeList.get(num);
    18 //        }
    19 //        if (t?his.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
    20             //强制竖屏模式
    21             parameters.set("orientation", "portrait");
    22             //在2.2以上可以使用,预览显示旋转90
    23 //        parameters.setRotation(90);
    24             camera.setDisplayOrientation(90);
    25 //        } else {
    26 //            parameters.set("orientation", "landscape");
    27             //在2.2以上可以使用
    28 //            camera.setDisplayOrientation(90);
    29 //        }
    30         camera.setParameters(parameters);
    31         try {
    32             //设置显示
    33             camera.setPreviewDisplay(holder);
    34         } catch (IOException exception) {
    35             camera.release();
    36             camera = null;
    37         }
    38         //开始预览
    39         camera.startPreview();
    40         //设置自动对焦
    41         camera.autoFocus(new Camera.AutoFocusCallback() {
    42             @Override
    43             public void onAutoFocus(boolean success, Camera camera) {
    44                 if (success) {
    45                     // success为true表示对焦成功,改变对焦状态图像
    46                 }
    47             }
    48         });
    49     }
    50 
    51     private Camera.Size getBestSize(List<Camera.Size> supportedPreviewSizes) {
    52         Camera.Size largestSize=supportedPreviewSizes.get(0);
    53         int largestArea= supportedPreviewSizes.get(0).height*supportedPreviewSizes.get(0).width;
    54         for (Camera.Size s:supportedPreviewSizes){
    55             int area=s.width*s.height;
    56             if(area>largestArea){
    57                 largestArea=area;
    58                 largestSize=s;
    59             }
    60         }
    61         return largestSize;
    62 
    63     }
    64 
    65     @Override
    66     public void surfaceDestroyed(SurfaceHolder holder) {
    67         // 释放手机摄像头
    68         camera.release();
    69     }

     也可以在surfaceChanged()中设置闪光灯等功能:

    1 parameters.setFlashMode(isChecked?Camera.Parameters.FLASH_MODE_ON:Camera.Parameters.FLASH_MODE_OFF);

    最后在需要摄像的点击监听中调用takePicture(Camera.ShutterCallback, Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)函数来完成拍照,这个函数中可以四个回调接口,ShutterCallback是快门按下的回调,在这里我们可以设置播放“咔嚓”声之类的操作,后面有三个PictureCallback接口,分别对应三份图像数据:原始图像、缩放和压缩图像和JPG图像,图像数据可以在PictureCallback接口的void onPictureTaken(byte[] data, Camera camera)中获得,三份数据相应的三个回调正好按照参数顺序调用,通常我们只关心JPG图像数据,此时前面两个PictureCallback接口参数可以直接传null

    每次调用takePicture() 获取图像后,摄像头会停止预览,假如需要继续拍照,则我们需要在上面的PictureCallbackonPictureTaken() 函数末尾,Camera对象再次调用startPreview() 函数;在不需要拍照的时候,Camera对象需要主动调用stopPreview() 停止预览功能;

    第二个功能是摄像图片的显示和保存,在这个功能中可能会出现两个问题,一个是拍摄图片横屏显示,另一个是将上边SurfaceView上方的ImageView遮罩层一同保存到用户手机,实现类似于图像合成的效果;

    关于图片横屏显示的问题,是因为Android官方认为手机横屏才是摄像头的正确打开方式,所以保存的图片也是横屏保存的,所以如果想竖屏显示图片,就要把图片顺时针旋转90度,调整到竖屏显示模式,具体代码如下:

    1 private void setImageByte(ImageView showImage, byte[] data) {
    2         Bitmap bitmap= BitmapFactory.decodeByteArray(data, 0, data.length);
    3         showImage.setImageBitmap(bitmap);
    4         Matrix matrix = showImage.getImageMatrix();
    5         matrix.setRotate(90);
    6         showImage.setImageBitmap(Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true));
    7     }

    还有一个问题是解决两个控件内容同时保存的问题,这个其实想到了方法就很简单了,自定义一个FrameLayout的子布局,在该布局中只加入一个方法

    1     public Bitmap getBitmap(){
    2         //设置缓存
    3         setDrawingCacheEnabled(true);
    4         buildDrawingCache();
    5         //从缓存中获取当前屏幕的图片
    6         return getDrawingCache();
    7     }

    然后在上文用到的xml布局中将该布局作为要同时保存图像的父控件。

    最后在java代码中需要保存合成图片的地方,只需要实例化刚刚自定义的FrameLayout对象调用getBitmap(),就能返回合成之后的Bitmap对象;

    所以我们的功能就能完全实现了。

  • 相关阅读:
    A1066 Root of AVL Tree (25 分)
    A1099 Build A Binary Search Tree (30 分)
    A1043 Is It a Binary Search Tree (25 分) ——PA, 24/25, 先记录思路
    A1079; A1090; A1004:一般树遍历
    A1053 Path of Equal Weight (30 分)
    A1086 Tree Traversals Again (25 分)
    A1020 Tree Traversals (25 分)
    A1091 Acute Stroke (30 分)
    A1103 Integer Factorization (30 分)
    A1032 Sharing (25 分)
  • 原文地址:https://www.cnblogs.com/BobGo/p/5646958.html
Copyright © 2011-2022 走看看