Android自定義Camera實現(xiàn)拍照功能
本文記錄了用自定義Camera實現(xiàn)的簡單拍照功能。
Camera類在5.0以后不推薦使用了,取而代之的是android.hardware.camera2包下的類,本文使用Camera。
我們首先自定義一個View去繼承SurfaceView:
public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Camera.AutoFocusCallback { private SurfaceHolder mHolder; private Camera mCamera; private static final int ORIENTATION = 90; private int mScreenWidth; private int mScreenHeight; private boolean isOpen; public CameraSurfaceView(Context context, AttributeSet attrs) { super(context, attrs); getScreenMatrix(context); mHolder = getHolder(); mHolder.addCallback(this); mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } private void getScreenMatrix(Context context) { WindowManager WM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics(); WM.getDefaultDisplay().getMetrics(outMetrics); mScreenWidth = outMetrics.widthPixels; mScreenHeight = outMetrics.heightPixels; } public void takePicture(Camera.ShutterCallback mShutterCallback, Camera.PictureCallback rawPictureCallback, Camera.PictureCallback jpegPictureCallback) { if (mCamera != null) mCamera.takePicture(mShutterCallback, rawPictureCallback, jpegPictureCallback); } public void startPreview() { mCamera.startPreview(); } @Override public void surfaceCreated(SurfaceHolder holder) { if (!checkCameraHardware(getContext())) return; if (mCamera == null) { isOpen = safeCameraOpen(Camera.CameraInfo.CAMERA_FACING_BACK); } if (!isOpen) { return; } mCamera.setDisplayOrientation(ORIENTATION); try { mCamera.setPreviewDisplay(holder); } catch (IOException e) { e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { if (mCamera != null) { setCameraParams(mScreenWidth, mScreenHeight); mCamera.startPreview(); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { releaseCameraAndPreview(); } private boolean safeCameraOpen(int id) { boolean qOpened = false; try { releaseCameraAndPreview(); mCamera = Camera.open(id); qOpened = (mCamera != null); } catch (Exception e) { e.printStackTrace(); } return qOpened; } private void releaseCameraAndPreview() { if (mCamera != null) { mCamera.stopPreview(); mCamera.release(); mCamera = null; } } private boolean checkCameraHardware(Context context) { if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) { return true; } else { return false; } } @Override public void onAutoFocus(boolean success, Camera camera) { } private void setCameraParams(int width, int height) { Camera.Parameters parameters = mCamera.getParameters(); // 獲取攝像頭支持的PictureSize列表 List<Camera.Size> pictureSizeList = parameters.getSupportedPictureSizes(); /**從列表中選取合適的分辨率*/ Camera.Size picSize = getProperSize(pictureSizeList, ((float) height / width)); if (null == picSize) { picSize = parameters.getPictureSize(); } // 根據(jù)選出的PictureSize重新設(shè)置SurfaceView大小 float w = picSize.width; float h = picSize.height; parameters.setPictureSize(picSize.width, picSize.height); this.setLayoutParams(new RelativeLayout.LayoutParams((int) (height * (h / w)), height)); // 獲取攝像頭支持的PreviewSize列表 List<Camera.Size> previewSizeList = parameters.getSupportedPreviewSizes(); Camera.Size preSize = getProperSize(previewSizeList, ((float) height) / width); if (null != preSize) { parameters.setPreviewSize(preSize.width, preSize.height); } parameters.setJpegQuality(100); // 設(shè)置照片質(zhì)量 if (parameters.getSupportedFocusModes().contains(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 連續(xù)對焦模式 } mCamera.setDisplayOrientation(90);// 設(shè)置PreviewDisplay的方向,效果就是將捕獲的畫面旋轉(zhuǎn)多少度顯示 mCamera.setParameters(parameters); } /** * 選取合適的分辨率 */ private Camera.Size getProperSize(List<Camera.Size> pictureSizeList, float screenRatio) { Camera.Size result = null; for (Camera.Size size : pictureSizeList) { float currentRatio = ((float) size.width) / size.height; if (currentRatio - screenRatio == 0) { result = size; break; } } if (null == result) { for (Camera.Size size : pictureSizeList) { float curRatio = ((float) size.width) / size.height; if (curRatio == 4f / 3) {// 默認w:h = 4:3 result = size; break; } } } return result; } }
代碼沒什么難度,在View創(chuàng)建的時候完成Camera的初始化,然后對Camera進行參數(shù)的設(shè)置(圖片尺寸,質(zhì)量之類的),最后別忘了在View銷毀的時候?qū)Y源進行釋放。
控件定義完了之后我們就要去使用它,在布局文件中添加就OK:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" > <com.padoon.cameratest.CameraSurfaceView android:id="@+id/sv_camera" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="4"/> <ImageView android:id="@+id/img_take_photo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_gravity="bottom" android:layout_marginBottom="10dp" android:layout_marginRight="10dp" android:src="@mipmap/icon_camera"/> </RelativeLayout>
然后在Activity中去完成拍照功能:
public class CameraActivity extends AppCompatActivity { private boolean isClick = true; private static final String PATH_IMAGES = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "easy_check"; private CameraSurfaceView mCameraSurfaceView; //拍照快門的回調(diào) private Camera.ShutterCallback mShutterCallback = new Camera.ShutterCallback() { @Override public void onShutter() { } }; //拍照完成之后返回原始數(shù)據(jù)的回調(diào) private Camera.PictureCallback rawPictureCallback = new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { } }; //拍照完成之后返回壓縮數(shù)據(jù)的回調(diào) private Camera.PictureCallback jpegPictureCallback = new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { mCameraSurfaceView.startPreview(); saveFile(data); Toast.makeText(CameraActivity.this, "拍照成功", Toast.LENGTH_SHORT).show(); isClick = true; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ImageView img_take_photo = (ImageView) findViewById(R.id.img_take_photo); mCameraSurfaceView = (CameraSurfaceView) findViewById(R.id.sv_camera); img_take_photo.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { takePhoto(); } }); } public void takePhoto() { if (isClick) { isClick = false; mCameraSurfaceView.takePicture(mShutterCallback, rawPictureCallback, jpegPictureCallback); } } //保存圖片到硬盤 public void saveFile(byte[] data) { String fileName = UUID.randomUUID().toString() + ".jpg"; FileOutputStream outputStream = null; try { File file = new File(PATH_IMAGES); if (!file.exists()) { file.mkdirs(); } outputStream = new FileOutputStream(PATH_IMAGES + File.separator + fileName); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream); bufferedOutputStream.write(data, 0, data.length); } catch (Exception e) { e.printStackTrace(); } finally { try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
最后記得添加拍照跟磁盤操作權(quán)限:
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
到這一個非常簡單的拍照Demo就完成了,只能當做Demo使用,離開發(fā)正式使用還有一段的距離,再次特地記錄一下。
下載:源碼
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android監(jiān)控和阻斷InputDispatching ANR的方法
如何在Java層實現(xiàn)異步監(jiān)控和阻斷InputDispatching ANR?我相信這是很多開發(fā)者都想要的功能,本篇,我們會通過“探索”兩種方案來實現(xiàn)在Java層監(jiān)控&阻斷的方法,需要的朋友可以參考下2024-04-04AndroidGUI27中findViewById返回null的快速解決辦法
這篇文章主要介紹了AndroidGUI27中findViewById返回null的快速解決辦法的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-06-06Android應用中使用ContentProvider掃描本地圖片并顯示
這篇文章主要介紹了Android應用中使用ContentProvider掃描本地圖片并顯示的方法,比調(diào)用本地圖庫的方法更加靈活和可定制,需要的朋友可以參考下2016-04-04

android ListView內(nèi)數(shù)據(jù)的動態(tài)添加與刪除實例代碼