最近公司新項目需要增加一個臉證功能,說白了就是需要在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) 就可以再次打開攝像頭