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 }