最近公司新项目需要增加一个脸证功能,说白了就是需要在SurefaceView上显示Camera预览当按钮点击后并把照片传给服务器进行匹配。
具体代码如下:
DisplayMetrics metric = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(metric);
int width = metric.widthPixels; // 屏幕宽度(像素)
int height = metric.heightPixels; // 屏幕高度(像素)
LayoutParams lp = surfaceView.getLayoutParams();
lp.height= height/2;
lp.width = width/2;
//在这里根据屏幕的宽高去设置surefaceView的宽高 不能自定义宽高 不然Camera拍出的照片会变形。
surfaceView.setLayoutParams(lp);
surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceView.getHolder().setFixedSize(200, 200);
surfaceView.getHolder().addCallback(new SurfaceViewCallback());
private final class SurfaceViewCallback implements SurfaceHolder.Callback {
/** * surfaceView 被创建成功后调用此方法 */
@SuppressWarnings("deprecation")
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.d(TAG, "surfaceCreated");
/* * 在SurfaceView创建好之后 打开摄像头 注意是 android.hardware.Camera */
// 此处判断是否有前置摄像头
try {
boolean isFrontFacingCamera = CheckCamera.hasFrontFacingCamera();
if (isFrontFacingCamera) {camera = Camera.open(1);
}else {
ToastUtil.showToast(mContext, "您的手机没有前置摄像头...");}}
catch (Exception e) {
e.printStackTrace();
ToastUtil.showToast(mContext,"没有拍照权限");
}/* * This method must be called before startPreview(). otherwise * surfaceview没有图像 */
try {
Camera.Parameters parameters = camera.getParameters();
Listrange = parameters.getSupportedPreviewFpsRange(); Log.i("msg", "range:"+range.size()); for(int j=0;j1){
parameters.setPreviewFpsRange(range.get(range.size()-1)[0], range.get(range.size()-1)[1]);
}
// parameters.setPreviewFrameRate(10);
注意这句话在Android 华为Mate8 华为P9手机上并不适用,因为每秒捕获多少帧是有硬件决定 所以这句话可以删掉(当初就是没删除这句话 折腾了好久)
parameters.setPictureFormat(PixelFormat.JPEG); // 设置照片的输出格式:jpg
parameters.setPreviewFormat(PixelFormat.YCbCr_420_SP); // picture,默认为NV21
// //横竖屏 切换 90°旋转
if (getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
parameters.set(ORIENTATION, PORTRAIT);
camera.setDisplayOrientation(90);// useful above 2.2
parameters.setRotation(90);
} else {
parameters.set(ORIENTATION, LANDSCAPE);
camera.setDisplayOrientation(0);// useful above 2.2
parameters.setRotation(0);
}
camera.setParameters(parameters);
camera.setPreviewDisplay(holder);
} catch (Exception e) {
e.printStackTrace();
Log.i("msg", "设置错误 ............");
}
camera.startPreview();
preview = true;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
/**
* SurfaceView 被销毁时释放掉 摄像头
*/
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (camera != null) {
/* 若摄像头正在工作,先停止它 */
if (preview) {
camera.stopPreview();
preview = false;
}
// 如果注册了此回调,在release之前调用,否则release之后还回调,crash
camera.setPreviewCallback(null);
camera.release();
}
}
}
/**
* 处理照片被拍摄之后的事件
*/
private final Camera.PictureCallback jpeg = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
String manuf=android.os.Build.MANUFACTURER; // 手机型号
String model = android.os.Build.MODEL;
LogUtils.e("厂商", manuf);
LogUtils.e("型号", model);
Bitmap bm = null;
if (manuf.equals("samsung")||manuf.equals("LGE")) {
//目前根据手机前置摄像头打开后的效果 暂时只发现 三星和LGE手机拍完照传给服务器的是旋转了90度的照片
bm = rotateBitmap(bitmap, 270);
}else {
bm = rotateBitmap(bitmap, 180);
}
ByteArrayOutputStream output = new ByteArrayOutputStream();// 初始化一个流对象
//这里对照片进行压缩,由于照片像素很高 所以必须压缩
Bitmap bm_result = BitmapUtil.ratio(bm,200,200);
bm_result.compress(Bitmap.CompressFormat.JPEG, 100, output);
// bm.recycle();// 自由选择是否进行回收
byte[] result = output.toByteArray();// 转换成功了
camera.stopPreview();
final String imgString = Base64.encodeToString(result, Base64.DEFAULT);
post(imgString);
}
};
//旋转代码
private Bitmap rotateBitmap(Bitmap src, int degrees) {
Matrix matrix = new Matrix();
matrix.reset();
matrix.setRotate(degrees);
Bitmap dstBitmap = Bitmap.createBitmap(src, 0, 0, src.getWidth(),
src.getHeight(), matrix, true);
src.recycle();
return dstBitmap;
}
拍照的话 在点击事件里面调用 camera.takePicture(null, null, jpeg);这句话就行。
在执行完一次拍照后需要继续预览(打开)前置摄像头需要
try {
camera.reconnect();
camera.startPreview();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
然后再重新调用camera.takePicture(null, null, jpeg) 就可以再次打开摄像头