Android Studio 呼叫Camera實現拍照功能
最近總想寫寫,但又不知寫些什麼,想了想,今天寫個Camera拍照的教程吧。本例子的流程為 首先通過SurfaceView將Camera的實時畫面顯示在螢幕上,然後通過點選拍照對當前畫面進行捕捉,最後將獲得的圖片儲存至本地。
- 首先建立一個SurfaceHolder實現對SurfaceView的回撥,然後重寫SurfaceCreate函式,實現對Camera的初始化等一系列工作:程式碼如下:
@Override public void surfaceCreated(SurfaceHolder holder) { Log.e("TAG","------surfaceCreated------"); try { //這裡我優先找後置攝像頭,找不到再找前面的 int cameraIndex = findBackOrFrontCamera(Camera.CameraInfo.CAMERA_FACING_BACK); if (cameraIndex == -1) { cameraIndex = findBackOrFrontCamera(Camera.CameraInfo.CAMERA_FACING_FRONT); if (cameraIndex == -1) { Log.e("TAG", "No Camera!"); currentCameraType = CAMERA_NOTEXIST; currentCameraIndex = -1; return; } else { currentCameraType = FRONT; } } else { currentCameraType = BACK; } //找到想要的攝像頭後,就開啟 if (mCamera == null) { mCamera = openCamera(currentCameraType); } } catch (Exception e) { e.printStackTrace(); } }
本例子中,我首先找到想要開啟的攝像頭,這裡的優先尋找後置攝像頭,如果沒有找到,再找前置的,程式碼如下:
/** * 按要求查詢攝像頭 * * @param camera_facing 按要求查詢,鏡頭是前還是後 * @return -1表示找不到 */ private int findBackOrFrontCamera(int camera_facing) { int cameraCount = 0; Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); cameraCount = Camera.getNumberOfCameras(); for (int camIdx = 0; camIdx < cameraCount; camIdx++) { Camera.getCameraInfo(camIdx, cameraInfo); if (cameraInfo.facing == camera_facing) { return camIdx; } } return -1; }
當找到攝像頭後,便開啟Camera,其實開啟Camera可以直接用open(CameraId)函式即可,但我在重新封裝了一下,直接帖程式碼:
/** * 按照type的型別開啟相應的攝像頭 * * @param type 標誌當前開啟前還是後的攝像頭 * @return 返回當前開啟攝像機的物件 */ private Camera openCamera(int type) { int frontIndex = -1; int backIndex = -1; int cameraCount = Camera.getNumberOfCameras(); Camera.CameraInfo info = new Camera.CameraInfo(); for (int cameraIndex = 0; cameraIndex < cameraCount; cameraIndex++) { Camera.getCameraInfo(cameraIndex, info); if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { frontIndex = cameraIndex; } else if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { backIndex = cameraIndex; } } currentCameraType = type; if (type == FRONT && frontIndex != -1) { currentCameraIndex = frontIndex; return Camera.open(frontIndex); } else if (type == BACK && backIndex != -1) { currentCameraIndex = backIndex; return Camera.open(backIndex); } return null; }
- 然後在SurfaceChange對Camera進行一系列初始化(對攝像頭初始化,就是設定圖片格式,圖片尺寸等賦值,要開啟攝像頭才可以初始化,否則會報錯)
/** * 初始化攝像頭 * @param holder */ private void initCamera(SurfaceHolder holder){ Log.e("TAG","initCamera"); if (mPreviewRunning) mCamera.stopPreview(); Camera.Parameters parameters; try{ //獲取預覽的各種解析度 parameters = mCamera.getParameters(); }catch (Exception e){ e.printStackTrace(); return; } //這裡我設為480*800的尺寸 parameters.setPreviewSize(480,800); // 設定照片格式 parameters.setPictureFormat(PixelFormat.JPEG); //設定圖片預覽的格式 parameters.setPreviewFormat(PixelFormat.YCbCr_420_SP); setCameraDisplayOrientation(this,currentCameraIndex,mCamera); try{ mCamera.setPreviewDisplay(holder); }catch(Exception e){ if(mCamera != null){ mCamera.release(); mCamera = null; } e.printStackTrace(); } mCamera.startPreview(); mPreviewRunning = true; } /** * 設定旋轉角度 * @param activity * @param cameraId * @param camera */ private void setCameraDisplayOrientation(Activity activity,int cameraId,Camera camera){ Camera.CameraInfo info = new Camera.CameraInfo(); Camera.getCameraInfo(cameraId,info); int rotation = activity.getWindowManager().getDefaultDisplay().getRotation(); int degrees = 0; switch(rotation){ case Surface.ROTATION_0: degrees = 0; break; case Surface.ROTATION_90: degrees = 90; break; case Surface.ROTATION_180: degrees = 180; break; case Surface.ROTATION_270: degrees = 270; break; } int result; if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){ result = (info.orientation + degrees) % 360; result = (360 - result) % 360; }else{ result = (info.orientation - degrees +360) % 360; } camera.setDisplayOrientation(result); }
- 當這些工作完成後,便可以對當前攝像頭捕捉的畫面進行拍照了:
/** * 實現拍照功能 */ public void takePhoto(){ Camera.Parameters parameters; try{ parameters = mCamera.getParameters(); }catch(Exception e){ e.printStackTrace(); return; } //獲取攝像頭支援的各種解析度,因為攝像頭陣列不確定是按降序還是升序,這裡的邏輯有時不是很好找得到相應的尺寸 //可先確定是按升還是降序排列,再進對對比吧,我這裡攏統地找了個,是個不精確的... List<Camera.Size> list = parameters.getSupportedPictureSizes(); int size = 0; for (int i =0 ;i < list.size() - 1;i++){ if (list.get(i).width >= 480){ //完美匹配 size = i; break; } else{ //找不到就找個最接近的吧 size = i; } } //設定照片解析度,注意要在攝像頭支援的範圍內選擇 parameters.setPictureSize(list.get(size).width,list.get(size).height); //設定照相機引數 mCamera.setParameters(parameters); //使用takePicture()方法完成拍照 mCamera.autoFocus(new Camera.AutoFocusCallback() { //自動聚焦完成後拍照 @Override public void onAutoFocus(boolean success, Camera camera) { if (success && camera != null){ mCamera.takePicture(new ShutterCallback(), null, new Camera.PictureCallback() { //拍照回撥介面 @Override public void onPictureTaken(byte[] data, Camera camera) { savePhoto(data); //停止預覽 mCamera.stopPreview(); //重啟預覽 mCamera.startPreview(); } }); } } }); } /* *//** * 快門回撥介面,如果不想拍照聲音,直接將new ShutterCallback()修改為null即可 */ private class ShutterCallback implements Camera.ShutterCallback { @Override public void onShutter() { MediaPlayer mPlayer = new MediaPlayer(); mPlayer = MediaPlayer.create(getApplicationContext(), R.raw.shutter); try{ mPlayer.prepare(); }catch (IllegalStateException e){ e.printStackTrace(); }catch (IOException e){ e.printStackTrace(); } mPlayer.start(); } }
這裡要注意下,有些手機呼叫onAutoFocus函式,會返回失敗,因為如果該手機無自動對焦,則無法執行對焦成功後的函式了。。。
-
當捕捉到資料後,便可以將這些資料儲存至設定的地方了:
/** * 設定照片的路徑,具體路徑可自定義 * @return */ private String setPicSaveFile(){ //建立儲存的路徑 File storageDir = getOwnCacheDirectory(this,"MyCamera/photos"); //返回自定義的路徑 return storageDir.getPath(); } private File getOwnCacheDirectory(Context context, String cacheDir) { File appCacheDir = null; //判斷SD卡正常掛載並且擁有根限的時候建立檔案 if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) && hasExternalStoragePermission(context)){ appCacheDir = new File(Environment.getExternalStorageDirectory(),cacheDir); } if (appCacheDir == null || !appCacheDir.exists() && !appCacheDir.mkdirs()){ appCacheDir = context.getCacheDir(); } return appCacheDir; } /** * 檢查是否有許可權 * @param context * @return */ private boolean hasExternalStoragePermission(Context context) { int permission = context.checkCallingOrSelfPermission("android.permission.WRITE_EXTERNAL_STORAGE"); //PERMISSION_GRANTED=0 return permission == 0; }
由於呼叫了系統Camera和對SD卡讀寫,所以在AndroidManifest需要申請許可權:
<!--攝像頭相關許可權--> <uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" /> <!-- 在SDCard中建立與刪除檔案許可權 --> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <!-- 往SDCard寫入資料許可權 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
後記:google在Android5.0後推出了Camera的升級版---Camera2:
按照Android的官方說明,camera 2支援以下5點新特性,有興趣的可以研究下:
(1)支援每秒30幀的全高清連拍。
(2)支援在每幀之間使用不同的設定。
(3)支援原生格式的影像輸出。
(4)支援零延遲快門和電影速拍。
(5)支援相機在其他方面的手動控制,比如設定噪音消除的級別。
最後也貼出本例子的原始碼吧,有興趣的可以到Github上下載本例子;如果支援本文,也可以直接在CSDN本站上下載github的連結地址:CSDN地址:https://download.csdn.net/download/toyauko/10636251
相關文章
- Android Camera——拍照Android
- Android自定義拍照實現Android
- Android呼叫攝像頭拍照Android
- android studio呼叫攝像頭拍照及具體步驟演示程式碼Android
- android實現拍照、相簿選圖、裁剪功能,相容7.0以及小米Android
- 純JavaScript實現的呼叫裝置攝像頭並拍照的功能JavaScript
- Android:呼叫系統相機實現拍照+裁切(相容7.0以上系統)Android
- Android camera2實現預覽Android
- 照片系列之android呼叫攝像頭拍照Android
- Android呼叫攝像頭拍照並顯示照片Android
- android studio模版功能簡介Android
- 【Android】【opencv】實現攝像頭拍照和錄影AndroidOpenCV
- Android 呼叫系統相機拍照 . 選取本地相簿Android
- Android Camera 系列(二)控制CameraAndroid
- android 拍照Android
- Android Studio NDK開發-JNI呼叫Java方法AndroidJava
- Android Studio 使用教程(二十一)之Android Studio 查詢功能(搜尋功能)及快捷鍵Android
- 短視訊程式開發,Android:呼叫系統拍照和相簿Android
- 在Android中呼叫攝像頭拍照並顯示出來Android
- Android 使用graphics.Camera類實現自定義旋轉飄落Android
- Android Studio3.4新功能和改進Android
- Android實現商城購物車功能Android
- Android Camera開發指南Android
- Android WebView 實現檔案選擇、拍照、錄製視訊、錄音AndroidWebView
- 【Camera專題】Qcom-如何修改Camera預覽、拍照、視訊時支援的解析度
- Android 拍照及相簿選取圖片功能,已適配Android6.0、7.0、8.0Android
- 【Camera專題】-Camera幀率、黃光環境下拍照閃紅問題-【展訊平臺】
- 安卓呼叫攝像頭拍照安卓
- android7.0以上呼叫系統相機拍照並顯示到ImageView上AndroidView
- Android手寫籤批功能實現(適配Android6Android
- Android Studio 對現代 WorkManager 的支援Android
- 基於Socket.IO實現Android聊天功能Android
- android 簡單實現指紋識別功能Android
- Android分享---呼叫系統自帶的分享功能Android
- Android 拍照新增時間水印Android
- 直播帶貨原始碼,Android Studio實現電商引導頁原始碼Android
- Android Camera瞭解一下Android
- android studio之簡單呼叫攝像頭並且獲取其照片Android