在Android 通常拍照主要有兩種方式,一種是調用系統相機,拍照以後獲取路徑顯示。而另一種則是調用Camera 而後去拍照。java
Ok,那麼今天講的是後者.主要是本身編寫代碼去完成拍照功能。android
首先咱們須要建一個 CameraPreview 類 ,固然也須要繼承 SurfaceView 並實現 SurfaceHolder.Callback接口,app
那麼該類主要是用做與顯示拍照預覽的。ide
import java.io.IOException; import java.util.List; import android.content.Context; import android.hardware.Camera; import android.hardware.Camera.Size; import android.util.AttributeSet; import android.view.SurfaceHolder; import android.view.SurfaceView; /** * 相機圖片預覽類 * * @author * */ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { public SurfaceHolder mHolder; private Camera mCamera; Size mPreviewSize; List<Size> mSupportedPreviewSizes; public CameraPreview(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public CameraPreview(Context context, AttributeSet attrs) { super(context, attrs); init(); } public CameraPreview(Context context) { super(context); init(); } /** * 初始化工做 * */ private void init() { // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. mHolder = getHolder(); mHolder.addCallback(this); // deprecated setting, but required on Android versions prior to 3.0 mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } // 設置相機 public void setCamera(Camera camera) { mCamera = camera; if (mCamera != null) { mSupportedPreviewSizes = mCamera.getParameters() .getSupportedPreviewSizes(); requestLayout(); } } @Override public void surfaceCreated(SurfaceHolder holder) { // The Surface has been created, now tell the camera where to draw the // preview. try { if (null != mCamera) { mCamera.setPreviewDisplay(holder); } } catch (IOException e1) { e1.printStackTrace(); } try { if (null != mCamera) { mCamera.startPreview(); } } catch (Exception e) { } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // If your preview can change or rotate, take care of those events here. // Make sure to stop the preview before resizing or reformatting it. if (null == mHolder.getSurface()) { // preview surface does not exist return; } // stop preview before making changes try { if (null != mCamera) { mCamera.stopPreview(); } } catch (Exception e) { // ignore: tried to stop a non-existent preview } // set preview size and make any resize, rotate or // reformatting changes here if (null != mCamera) { Camera.Parameters parameters = mCamera.getParameters(); parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); requestLayout(); mCamera.setParameters(parameters); mCamera.setDisplayOrientation(90); } // 這裏能夠用來設置尺寸 // start preview with new settings try { if (null != mCamera) { mCamera.setPreviewDisplay(mHolder); mCamera.startPreview(); } } catch (Exception e) { } } @Override public void surfaceDestroyed(SurfaceHolder holder) { if (null != mCamera) { mCamera.stopPreview(); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // We purposely disregard child measurements because act as a // wrapper to a SurfaceView that centers the camera preview instead // of stretching it. final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec); final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec); setMeasuredDimension(width, height); if (mSupportedPreviewSizes != null) { mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height); } } private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) { final double ASPECT_TOLERANCE = 0.1; double targetRatio = (double) w / h; if (sizes == null) return null; Size optimalSize = null; double minDiff = Double.MAX_VALUE; int targetHeight = h; // Try to find an size match aspect ratio and size for (Size size : sizes) { double ratio = (double) size.width / size.height; if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } // Cannot find the one match the aspect ratio, ignore the requirement if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (Size size : sizes) { if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } } return optimalSize; } }
首先你能夠本身定義一個佈局,而後搞上該類。但今天不寫佈局,直接用代碼生成。佈局
ok ,那麼咱們須要先定義一下須要用到的變量。ui
private Camera mCamera; // 相機 int mDefaultCameraId; // 默認相機ID private CameraPreview mPreview; // 集成SurfaceView 的類 int mScreenWidth, mScreenHeight; // 屏幕寬和高 FrameLayout preview; // 佈局 private File saveVideoFile; // 保存文件
// 無標題欄的窗口 requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); // 選擇支持半透明模式,在有surfaceview的activity中使用。 getWindow().setFormat(PixelFormat.TRANSLUCENT); // 獲得屏幕的大小 WindowManager wManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); Display display = wManager.getDefaultDisplay(); mScreenHeight = display.getHeight(); mScreenWidth = display.getWidth(); mPreview = new CameraPreview(this); preview = new FrameLayout(getApplicationContext()); // 將相機預覽圖加入幀佈局裏面 preview.addView(mPreview, 0); setContentView(preview); <pre style="background-color:#ffffff;color:#000000;font-family:'宋體';font-size:9.0pt;"><span style="background-color:#ffe4ff;"> mDefaultCameraId</span> = CameraUtils.<span style="font-style:italic;">getDefaultCameraId</span>();
import android.hardware.Camera; import android.view.SurfaceView; import android.widget.FrameLayout; import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by on 16-2-29. */ public class CameraUtils { /** * 獲取默認的相機 * @return */ public static int getDefaultCameraId(){ int defaultId = -1; // Find the total number of cameras available int mNumberOfCameras = Camera.getNumberOfCameras(); // 獲得攝像頭個數 // Find the ID of the default camera Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); for (int i = 0; i < mNumberOfCameras; i++) { Camera.getCameraInfo(i, cameraInfo); if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { defaultId = i; } } if (-1 == defaultId) { if (mNumberOfCameras > 0) { // 若是沒有後向攝像頭 defaultId = 0; } else { //沒有攝像頭 return -1; // 沒有攝像頭 } } return defaultId; } /** * 打開相機 * @param cameraId 鏡頭ID 0位前置 1爲後置 * @param exception 錯誤信息, 若是打開錯誤 則賦值給他 * @return 不爲NULL 則打開成功 */ public static Camera getCameraInstance(int cameraId,Exception exception) { Camera c = null; try { c = Camera.open(cameraId); // attempt to get a Camera instance if (cameraId == Camera.CameraInfo.CAMERA_FACING_BACK) { Camera.Parameters params = c.getParameters(); params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); // 設置聚焦方式 c.setParameters(params); } } catch (Exception e) { // Camera is not available (in use or does not exist) e.printStackTrace(); exception = e; return null; } return c; // returns null if camera is unavailable } public static final int MEDIA_TYPE_IMAGE = 1; public static final int MEDIA_TYPE_VIDEO = 2; /** * 獲取輸出文件類型 * @param type 1 Image 2爲VIDEO * @param saveFilePath 保存文件路徑 須要在尾加上/ * @return File 類 錯誤則爲空 */ public static File getOutputMediaFile(int type,String saveFilePath) { File mediaStorageDir = null; try { mediaStorageDir = new File(saveFilePath); } catch (Exception e) { e.printStackTrace(); } // Create the storage directory if it does not exist if (!mediaStorageDir.exists()) { if (!mediaStorageDir.mkdirs()) { // 在SD卡上建立文件夾須要權限: // <uses-permission // android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> return null; } } // Create a media file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss") .format(new Date()); File mediaFile; if (type == MEDIA_TYPE_IMAGE) { mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg"); } else if (type == MEDIA_TYPE_VIDEO) { mediaFile = new File(mediaStorageDir.getPath() + File.separator + "VID_" + timeStamp + ".mp4"); } else { return null; } return mediaFile; } /** * 釋放相機 * @param mCamera 相機 * @throws Exception */ public static void releaseCamera(Camera mCamera) throws Exception { if (mCamera != null) { mCamera.setPreviewCallback(null); mCamera.stopPreview();// 停掉原來攝像頭的預覽 Camera.Parameters p = mCamera.getParameters(); if (p.getFlashMode().equals(Camera.Parameters.FLASH_MODE_TORCH)) p.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); p.setZoom(0); mCamera.setParameters(p); mCamera.release(); mCamera = null; } } }
mCamera = CameraUtils.getCameraInstance(mDefaultCameraId=0,mException); if(mCamera == null){ Log.v(TAG,"open Camera Error"); return ; } mPreview.setCamera(mCamera); mCamera.startPreview();
寫一個內部類this
/** * 拍照 */ private Camera.PictureCallback mPicture = new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { File pictureFile = CameraUtils.getOutputMediaFile(CameraUtils.MEDIA_TYPE_IMAGE,saveFilePath); if (pictureFile == null) { return; } try { FileOutputStream fos = new FileOutputStream(pictureFile); fos.write(data); fos.close(); } catch (FileNotFoundException e) { Log.d(TAG, e.getMessage()); } catch (IOException e) { Log.d(TAG, e.getMessage()); } // 拍照後從新開始預覽 mCamera.stopPreview(); mCamera.startPreview(); } };
mCamera.takePicture(null, null, mPicture);那麼到這裏就完成一個拍照功能的應用了。