摄像头(4)用Camera和SurfaceView自定义拍照程序

1.定制拍照程序的基本步骤

  1,打开照相机:Camera.open 这是独占方式打开的

  2,创建SurfaceView对象 多缓冲,多线程view

  3,添加回调事件监听器(SurfaceHolder.addCallback)

  4,预览(Camera.startPreview)

  5,拍照(Camera.takePicture),它是异步的,要在参数中指定回调函数

2.示例

2.1 主activity

 1 import android.app.Activity;
 2 import android.content.pm.PackageManager;
 3 import android.hardware.Camera;
 4 import android.os.Bundle;
 5 import android.view.Window;
 6 import android.view.WindowManager;
 7 
 8 
 9 /*
10  * 定制拍照程序
11  * 注意Camera从5.0开始过期.用Camera2
12  */
13 public class CustomCameraActivity extends Activity {
14     
15     //定制拍照 第1步,加权限
16     
17     //定制拍照 第2步,准备相关api
18     private Camera mCamera;//用来拍照
19     
20     private Preview mPreview;//用来预览和处理拍照事件.它是一个自定义surfaceView
21 
22     @Override
23     protected void onCreate(Bundle savedInstanceState) {
24         super.onCreate(savedInstanceState);
25         
26         //定制拍照 第3步,设置全屏.
27         requestWindowFeature(Window.FEATURE_NO_TITLE);
28         getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
29         
30     }
31 
32     protected void onResume() {
33         super.onResume();
34         //定制拍照 第4步, 打开 Camera并得到Camera实例,注意这是独占的,打开后其它程序不能打开.
35         mCamera = Camera.open();
36         mPreview.setCamera(mCamera);
37         
38         //定制拍照 第5步,构造预览view,这是一个自定义的surfaceView,拍照事件,及预览都在它内部实现.
39         mPreview = new Preview(this);
40         setContentView(mPreview);
41     }
42 
43     //定制拍照 第6步,释放camera 
44     @Override
45     protected void onPause() {
46         super.onPause();
47 
48         if (mCamera != null) {
49             mCamera.release();
50             mCamera = null;
51             mPreview.setCamera(null);
52         }
53     }
54     
55     //检测Android设备是否支持照相机
56     private boolean checkCameraHardware(){
57         if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
58             return true;
59         }else{
60             return false;
61         }
62     }
63 }

2.2 用来预览和处理拍照事件的类,关键

  1 import java.io.File;
  2 import java.io.FileOutputStream;
  3 import java.util.List;
  4 
  5 import android.content.Context;
  6 import android.hardware.Camera;
  7 import android.hardware.Camera.PictureCallback;
  8 import android.hardware.Camera.Size;
  9 import android.view.SurfaceHolder;
 10 import android.view.SurfaceView;
 11 import android.view.View;
 12 import android.view.ViewGroup;
 13 import android.view.View.OnClickListener;
 14 
 15 /*
 16  * 它是一个自定义surfaceView,
 17  * 用来预览和处理拍照事件.
 18  * 注意它实现的接口
 19  */
 20 class Preview extends ViewGroup implements SurfaceHolder.Callback,OnClickListener {
 21 
 22     //自定义预览和处理拍照事件 第1步, 准备相关成员
 23     SurfaceView mSurfaceView;             //surface view
 24     SurfaceHolder mHolder;                //SurfaceHolder
 25     Size mPreviewSize;                    //当前预览窗口尺寸.
 26     List<Size> mSupportedPreviewSizes;    //当前设备支持的所有预览尺寸
 27     Camera mCamera;                        //摄像头对象
 28     Context mContext;                    //上下文
 29 
 30     public Preview(Context context) {
 31         super(context);
 32         mContext = context;
 33         
 34         //自定义预览和处理拍照事件 第2步,创建surface view
 35         mSurfaceView = new SurfaceView(context);
 36         addView(mSurfaceView);
 37         //自定义预览和处理拍照事件 第3步,得到 SurfaceHolder
 38         mHolder = mSurfaceView.getHolder();
 39         
 40         //自定义预览和处理拍照事件 第4步,添加SurfaceHolder回调
 41         mHolder.addCallback(this);
 42     }
 43     public void setCamera(Camera camera) {
 44         mCamera = camera;
 45         if (mCamera != null) {
 46             //自定义预览和处理拍照事件 第5步,得到支持的预览尺寸,注意Camera是在本类外打开的.
 47             mSupportedPreviewSizes = mCamera.getParameters().getSupportedPictureSizes();
 48             //更新 layout
 49             requestLayout();
 50         }
 51     }
 52     //from  SurfaceHolder.Callback
 53     @Override
 54     public void surfaceCreated(SurfaceHolder holder) {
 55         try {
 56             if (mCamera != null) {
 57                 //自定义预览和处理拍照事件 第6步,在SurfaceView创建时,设置camera的预览view
 58                 mCamera.setPreviewDisplay(holder);
 59             }
 60         } catch (Exception e) {
 61         }
 62 
 63     }
 64     //from  SurfaceHolder.Callback
 65     @Override
 66     public void surfaceDestroyed(SurfaceHolder holder) {
 67         if (mCamera != null) {
 68             //自定义预览和处理拍照事件 第7步,在SurfaceView销毁时,停止预览
 69             mCamera.stopPreview();
 70         }
 71     }
 72     //from  SurfaceHolder.Callback
 73     @Override
 74     public void surfaceChanged(SurfaceHolder holder, int format, int width,
 75             int height) {
 76         //自定义预览和处理拍照事件 第8步,在SurfaceView窗口大小变化时,设置预览尺寸,大小不可随意写.
 77         //一定要注意 预览尺寸不是实际尺寸,
 78         Camera.Parameters parameters = mCamera.getParameters();
 79         parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
 80 
 81         mCamera.setParameters(parameters);
 82         mCamera.startPreview();
 83 
 84     }
 85     //from ViewGroup
 86     @Override
 87     protected void onLayout(boolean changed, int l, int t, int r, int b) {
 88         //自定义预览和处理拍照事件 第9步,是本类是ViewGroup,预览view是它上面的一个view,这里设置ViewGroup的layout
 89         if (changed && getChildCount() > 0) {
 90             final View child = getChildAt(0);
 91 
 92             int parentWidth = r - l;
 93             int parentHeight = b - t;
 94 
 95             int previewWidth = parentWidth;
 96             int previewHeight = parentHeight;
 97 
 98             if (mPreviewSize != null) {
 99                 previewWidth = mPreviewSize.width;
100                 previewHeight = mPreviewSize.height;
101             }
102             //外层的宽高比大于采集预览的宽高比.
103             if (parentWidth * previewHeight > parentHeight * previewWidth) {
104                 final int scaledChildWidth = previewWidth * parentHeight
105                         / previewHeight;
106                 // child.layout((width - scaledChildWidth)/2,
107                 // 0,(width+scaledChildWidth)/2,height);
108 
109                 //child 就是surface view
110                 child.layout(100, 100, 340, 240);
111             } else {
112                 final int scaledChildHeight = previewHeight * parentWidth
113                         / previewWidth;
114                 //child 就是surface view
115                 child.layout(0, (parentHeight - scaledChildHeight) / 2, parentWidth,
116                         (parentHeight + scaledChildHeight) / 2);
117             }
118 
119         }
120 
121     }
122     //自定义预览和处理拍照事件 第10步,从所有预览尺寸中选一个最优的.
123     private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
124         double ASPECT_TOLERANCE = 0.1;
125         double targetRatio = w / h;
126         if (sizes == null)
127             return null;
128 
129         Size optimalSize = null;
130         double minDiff = Double.MAX_VALUE;
131         int targetHeight = h;
132 
133         for (Size size : sizes) {
134             double ratio = size.width / size.height;
135             if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) {
136                 continue;
137             }
138             if (Math.abs(size.height - targetHeight) < minDiff) {
139                 optimalSize = size;
140                 minDiff = Math.abs(size.height - targetHeight);
141             }
142         }
143 
144         if (optimalSize == null) {
145             minDiff = Double.MAX_VALUE;
146             for (Size size : sizes) {
147                 if (Math.abs(size.height - targetHeight) < minDiff) {
148                     optimalSize = size;
149                     minDiff = Math.abs(size.height - targetHeight);
150                 }
151             }
152         }
153         return optimalSize;
154     }
155 
156     //自定义预览和处理拍照事件 第11步,在onMeasure中处理最佳预览尺寸
157     @Override
158     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
159         int width = resolveSize(getSuggestedMinimumWidth(),
160                 widthMeasureSpec);
161         int height = resolveSize(getSuggestedMinimumHeight(),
162                 heightMeasureSpec);
163 
164         setMeasuredDimension(width, height);
165 
166         if (mSupportedPreviewSizes != null) {
167             mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes,width, height);
168         }
169     }
170     //自定义预览和处理拍照事件 第12步, 在预览view上点击屏幕时,拍照
171     //注意回调函数
172     public void onClick(View view) {
173         //它是异步的.
174         mCamera.takePicture(null, null, mPictureCallback);
175     }
176     
177     //自定义预览和处理拍照事件 第13步, 拍照的回调.
178     private PictureCallback mPictureCallback = new PictureCallback() {
179 
180         @Override
181         public void onPictureTaken(byte[] data, Camera camera) {
182             mCamera.startPreview();//再次启动预览,这步可选.
183             File pictureFile = new File("/sdcard/image.jpg");
184             try {
185                 FileOutputStream fos = new FileOutputStream(pictureFile);
186                 fos.write(data);
187                 fos.close();
188             } catch (Exception e) {
189             }
190         }
191     };
192 }

 

转载于:https://www.cnblogs.com/sjjg/p/4789202.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值