Android Camera開發實現可復用的相機組件
本文實例為大傢分享瞭Android Camera實現可復用相機組件的具體代碼,供大傢參考,具體內容如下
若自己的應用需要使用camera,有兩種解決方案。
1. 使用Intent調用自帶的Camera程序
2. 使用Camera API在程序中構造自己的Camera。
本文主要講解第二種。
構造一個相機APP,通常需要六個步驟
1. 聲明Manifest的相機權限
2. 創建一個相機預覽類(繼承SurfaceView)
3. 創建一個類實現相機拍照之後的回調函數
本文將一步步帶你實現上述三個步驟。
1. 聲明Manifest的相機權限。
應為我們需要寫文件與調用相機,所以在你的manifest文件中加上。
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2. 創建一個相機預覽類
由於相機的預覽是使用的SurfaceView,所以這裡我們創建一個SurfaceView的子類。
為瞭讓這個View所見即所得,我們將其設置為4/3的比例。重寫它的onMeasure方法
代碼如下:
package com.example.cameratutorial; import android.content.Context; import android.util.Log; import android.view.SurfaceView; /** * @author CTGU小龍同學 2014-6-21 */ public class CameraSurfaceView extends SurfaceView { private static final String TAG = "CameraSurfaceView"; // 用四比三的比例 public static double RATIO = 3.0 / 4.0; /** * @param context */ public CameraSurfaceView(Context context) { super(context); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height = MeasureSpec.getSize(heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); Log.d("Measured", "before width" + width + "height" + height); boolean isWidthLonger; int longSide; int shortSide; // 以短邊為準確定一下長邊 if (width < height) { height = (int) (width / RATIO); isWidthLonger = false; } else { width = (int) (height / RATIO); isWidthLonger = true; } Log.d("Measured", "after width" + width + "height" + height); setMeasuredDimension(width, height); } }
3. 現在我們使用一個實現瞭SurfaceHolder.Callback, Camera.PictureCallback 的Fragment來把我們需要的組件都封裝起來。
代碼如下:
package com.example.cameratutorial; import java.io.*; import java.util.*; import android.app.Activity; import android.app.Fragment; import android.graphics.*; import android.graphics.Bitmap.CompressFormat; import android.hardware.Camera; import android.hardware.Camera.CameraInfo; import android.hardware.Camera.Size; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.*; import android.widget.RelativeLayout; import android.widget.Toast; /** * @author CTGU小龍同學 2014-6-21 */ public class CameraFragment extends Fragment implements SurfaceHolder.Callback, Camera.PictureCallback { private Camera mCamera; // CameraPreview的holder private SurfaceHolder mSurfaceHolder; private CameraSurfaceView preview; private int mFrontCameraId = -1; private int mBackCameraId = -1; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { preview = new CameraSurfaceView(getActivity()); preview.getHolder().addCallback(this); RelativeLayout layout = new RelativeLayout(getActivity()); layout.addView(preview); return layout; } @Override public void onAttach(Activity activity) { super.onAttach(activity); findAvailableCameras(); } @Override public void onResume() { super.onResume(); Log.d("camera", "mFrontCameraId" + mFrontCameraId); Log.d("camera", "mbackCameraId" + mBackCameraId); if (mBackCameraId != -1) { mCamera = Camera.open(mBackCameraId); } else { Toast.makeText(getActivity(), "fialed to open camera", Toast.LENGTH_SHORT).show(); } } @Override public void onPause() { super.onPause(); mCamera.stopPreview(); mCamera.release(); } /** * 獲得可用的相機,並設置前後攝像機的ID */ private void findAvailableCameras() { Camera.CameraInfo info = new CameraInfo(); int numCamera = Camera.getNumberOfCameras(); for (int i = 0; i < numCamera; i++) { Camera.getCameraInfo(i, info); // 找到瞭前置攝像頭 if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { mFrontCameraId = info.facing; } // 招到瞭後置攝像頭 if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { mBackCameraId = info.facing; } } } /** * 當相機拍照時會回調該方法 */ @Override public void onPictureTaken(byte[] data, Camera camera) { final Bitmap bitmap; final String path; try { // /storage/emulated/0/Pictures/XXX.jpg path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath() + "/" + new Date().toLocaleString() + ".jpg"; Log.d("Path", path); bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); camera.stopPreview(); final int displayOrientation = getCorrectOrientation(); new Thread(new Runnable() { @Override public void run() { FileOutputStream fos; Matrix matrix = new Matrix(); matrix.postRotate(displayOrientation); Bitmap rotaBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false); try { fos = new FileOutputStream(path); rotaBitmap.compress(CompressFormat.JPEG, 100, fos); fos.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); } catch (Exception e) { } camera.startPreview(); } /** * 讓預覽跟照片符合正確的方向。<br/> * 因為預覽默認是橫向的。如果是一個豎向的應用,就需要把預覽轉90度<br/> * 比如橫著時1280*960的尺寸時,1280是寬.<br/> * 豎著的時候1280就是高瞭<br/> * 這段代碼來自官方API。意思就是讓拍出照片的方向和預覽方向正確的符合設備當前的方向(有可能是豎向的也可能使橫向的) * */ private int getCorrectOrientation() { android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); android.hardware.Camera.getCameraInfo(mBackCameraId, info); int rotation = getActivity().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; // compensate the mirror } else { // back-facing result = (info.orientation - degrees + 360) % 360; } Log.d("orientationResult", result + ""); return result; } public void takePicture() { mCamera.takePicture(null, null, this); } @Override public void surfaceCreated(SurfaceHolder holder) { mSurfaceHolder = holder; startPreView(); } private void startPreView() { try { mCamera.setPreviewDisplay(mSurfaceHolder); setPreviewSize(); setDisplayOrientation(); mCamera.startPreview(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void setDisplayOrientation() { int displayOrientation = getCorrectOrientation(); mCamera.setDisplayOrientation(displayOrientation); } /** * 我們用4比3的比例設置預覽圖片 */ private void setPreviewSize() { Camera.Parameters params = mCamera.getParameters(); List<Size> sizes = params.getSupportedPreviewSizes(); for (Size size : sizes) { Log.d("previewSize", "width:" + size.width + " height " + size.height); } for (Size size : sizes) { if (size.width / 4 == size.height / 3) { params.setPreviewSize(size.width, size.height); Log.d("previewSize", "SET width:" + size.width + " height " + size.height); break; } } // params一定要記得寫回Camera mCamera.setParameters(params); } private void setPictureSize() { Camera.Parameters params = mCamera.getParameters(); List<Size> sizes = params.getSupportedPictureSizes(); for (Size size : sizes) { Log.d("picSize", "width:" + size.width + " height " + size.height); } for (Size size : sizes) { if (size.width / 4 == size.height / 3) { params.setPictureSize(size.width, size.height); break; } } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { mCamera.release(); } }
4. 程序的Mainactivity以及相應的佈局文件
package com.example.cameratutorial; import android.os.Bundle; import android.app.Activity; import android.app.FragmentManager; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final CameraFragment fragment=(CameraFragment) getFragmentManager().findFragmentById(R.id.camera_fragment); Button button=(Button) findViewById(R.id.TakePic); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { fragment.takePicture(); } }); } }
佈局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <fragment android:id="@+id/camera_fragment" android:name="com.example.cameratutorial.CameraFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> <Button android:id="@+id/TakePic" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:text="capture" /> </RelativeLayout>
這樣,我們一個可以復用的相機組件就完成瞭
下一篇文章應該是關於如何實現觸摸對焦測光的。
以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。
推薦閱讀:
- Android 錄制音視頻的完整代碼
- Android利用zxing生成二維碼的過程記錄
- Android實現文字消除效果
- ViewPager+Fragment實現側滑導航欄
- Android利用SoundPool實現音樂池