Android Camera拍照实现

来源:互联网 发布:大数据和股票有哪些 编辑:程序博客网 时间:2024/03/29 07:45

        既然都已经学了如何打开Camera,那么就顺着官方API的引导,实现一下Camera拍照的功能吧!

        百度了一下Android Camera拍照的功能实现,其中yanzi1225627是我认为写得比较好的,所以我也是照着他的思路实现的拍照功能实现,但是有个问题是,我按博主的代码实现后,SurfaceView中预览不到,其中的原因在我上一篇博文有讲解到,所以在这里,我对其代码进行了简单的修改后,就没有问题了!

         首先是布局文件,我并没有作任何修改:

<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"    tools:context="org.hwm.app.photograph.PhotographActivity" >    <FrameLayout          android:layout_width="wrap_content"          android:layout_height="wrap_content" >            <org.hwm.app.photograph.PhotographSurface              android:id="@+id/surfaceview"              android:layout_width="0dip"              android:layout_height="0dip" />      </FrameLayout>        <ImageButton          android:id="@+id/btn_shutter"          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:layout_alignParentBottom="true"          android:layout_centerHorizontal="true"           android:layout_marginBottom="10dip"/>      </RelativeLayout>

        其次是AndroidManifest.xml文件,需要注意的是,在使用autofocus时,应该再加个android:required="false",不然事实证明,并不能聚焦,所以修改如下:

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="org.hwm.app.photograph"    android:versionCode="1"    android:versionName="1.0" >    <uses-sdk        android:minSdkVersion="8"        android:targetSdkVersion="21" />        <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />      <uses-permission android:name="android.permission.CAMERA" />       <uses-feature android:name="android.hardware.camera" android:required="false"/>    <uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>    <application        android:allowBackup="true"        android:icon="@drawable/ic_launcher"        android:label="@string/app_name"        android:theme="@style/AppTheme" >        <activity            android:name=".PhotographActivity"            android:label="@string/app_name"            android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"              android:screenOrientation="portrait" >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application></manifest>

        下面是Java代码的实现部分,先让我们来看一下工具类的实现,工具类还是一模一样的:

1. ImageUtil.java : 对得到的照片进行旋转处理。

package org.hwm.app.util;import android.graphics.Bitmap;import android.graphics.Matrix;public class ImageUtil {      /**      * Rotate Bitmap      * @param b      * @param rotateDegree      * @return      */      public static Bitmap getRotateBitmap(Bitmap b, float rotateDegree){          Matrix matrix = new Matrix();          matrix.postRotate((float)rotateDegree);          Bitmap rotaBitmap = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), matrix, false);          return rotaBitmap;      }  } 

2. FileUtil.java:设置照片的保存路径。

package org.hwm.app.util;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import android.graphics.Bitmap;import android.os.Environment;import android.util.Log;public class FileUtil {      private static final  String TAG = "FileUtil";      private static final File parentPath = Environment.getExternalStorageDirectory();      private static   String savePath = "";      private static final String SAVE_FOLDER_NAME = "Photograph";        /**Initiate savePath     * @return      */      private static String initPath(){          if(savePath.equals("")){          savePath = parentPath.getAbsolutePath()+"/" + SAVE_FOLDER_NAME;              File f = new File(savePath);              if(!f.exists()){                  f.mkdir();              }          }          return savePath;      }        /**save Bitmap to sdcard      * @param b      */      public static void saveBitmap(Bitmap b){          String path = initPath();          long dataTake = System.currentTimeMillis();          String jpegName = path + "/" + dataTake +".jpg";          Log.i(TAG, "saveBitmap:jpegName = " + jpegName);          try {              FileOutputStream fos = new FileOutputStream(jpegName);              BufferedOutputStream bos = new BufferedOutputStream(fos);              b.compress(Bitmap.CompressFormat.JPEG, 100, bos);              bos.flush();              bos.close();              Log.i(TAG, "saveBitmap successed");          } catch (IOException e) {              // TODO Auto-generated catch block              Log.i(TAG, "saveBitmap failed");              e.printStackTrace();          }      }  }

3. DisplayUtil

package org.hwm.app.util;import android.content.Context;import android.graphics.Point;import android.util.DisplayMetrics;import android.util.Log;public class DisplayUtil {      private static final String TAG = "DisplayUtil";      /**      * dip to px      * @param context      * @param dipValue      * @return      */      public static int dip2px(Context context, float dipValue){                      final float scale = context.getResources().getDisplayMetrics().density;                           return (int)(dipValue * scale + 0.5f);               }                 /**      * px to dip      * @param context      * @param pxValue      * @return      */      public static int px2dip(Context context, float pxValue){                          final float scale = context.getResources().getDisplayMetrics().density;                           return (int)(pxValue / scale + 0.5f);               }             /**      * Obtain the width and height of screen      * @param context      * @return      */      public static Point getScreenMetrics(Context context){          DisplayMetrics dm =context.getResources().getDisplayMetrics();          int w_screen = dm.widthPixels;          int h_screen = dm.heightPixels;          Log.i(TAG, "Screen---Width = " + w_screen + " Height = " + h_screen + " densityDpi = " + dm.densityDpi);          return new Point(w_screen, h_screen);                }            /**      * Obtain the rate of width and height     * @param context      * @return      */      public static float getScreenRate(Context context){          Point P = getScreenMetrics(context);          float H = P.y;          float W = P.x;          return (H/W);      }  }  

4. CamParamUtil.java :解析Camera的参数

package org.hwm.app.util;import java.util.Collections;import java.util.Comparator;import java.util.List;import android.hardware.Camera;import android.hardware.Camera.Size;import android.util.Log;public class CamParaUtil {      private static final String TAG = "CamParaUtil";      private CameraSizeComparator sizeComparator = new CameraSizeComparator();      private static CamParaUtil myCamPara = null;          private CamParaUtil(){      }          public static CamParaUtil getInstance(){          if(myCamPara == null){              myCamPara = new CamParaUtil();          }          return myCamPara;      }        public  Size getPropPreviewSize(List<Camera.Size> list, float th, int minWidth){          Collections.sort(list, sizeComparator);          int i = 0;          for(Size s:list){              if((s.width >= minWidth) && equalRate(s, th)){                  Log.i(TAG, "PreviewSize:w = " + s.width + "h = " + s.height);                  break;              }              i++;          }          if(i == list.size()){              i = 0;//set the minimum one         }          return list.get(i);      }          public Size getPropPictureSize(List<Camera.Size> list, float th, int minWidth){          Collections.sort(list, sizeComparator);          int i = 0;          for(Size s:list){              if((s.width >= minWidth) && equalRate(s, th)){                  Log.i(TAG, "PictureSize : w = " + s.width + "h = " + s.height);                  break;              }              i++;          }          if(i == list.size()){              i = 0;//set the minimum one          }          return list.get(i);      }        public boolean equalRate(Size s, float rate){          float r = (float)(s.width)/(float)(s.height);          if(Math.abs(r - rate) <= 0.03)          {              return true;          }          else{              return false;          }      }        public  class CameraSizeComparator implements Comparator<Camera.Size>{     @Override        public int compare(Size lhs, Size rhs) {              if(lhs.width == rhs.width){                  return 0;              }              else if(lhs.width > rhs.width){                  return 1;              }              else{                  return -1;              }          }        }        /**Print previewSizes      * @param params      */      public  void printSupportPreviewSize(Camera.Parameters params){          List<Size> previewSizes = params.getSupportedPreviewSizes();          for(int i=0; i< previewSizes.size(); i++){              Size size = previewSizes.get(i);              Log.i(TAG, "previewSizes:width = "+size.width+" height = "+size.height);          }            }        /**Print pictureSizes      * @param params      */      public  void printSupportPictureSize(Camera.Parameters params){          List<Size> pictureSizes = params.getSupportedPictureSizes();          for(int i=0; i< pictureSizes.size(); i++){              Size size = pictureSizes.get(i);              Log.i(TAG, "pictureSizes:width = "+ size.width                      +" height = " + size.height);          }      }      /**Print supportFocusMode     * @param params      */      public void printSupportFocusMode(Camera.Parameters params){          List<String> focusModes = params.getSupportedFocusModes();          for(String mode : focusModes){              Log.i(TAG, "focusModes--" + mode);          }      }  }

5. PhotographSurface.java :和原博主的SurfaceView不同,类中,我通过setCamera方法为PhotographSurface类传入Camera对象,并在surfaceCreated的方法中为传入的Camera设置Holder,这也是我和原博主的主要不同。

package org.hwm.app.photograph;import android.content.Context;import android.hardware.Camera;import android.util.AttributeSet;import android.util.Log;import android.view.SurfaceHolder;import android.view.SurfaceView;public class PhotographSurface extends SurfaceView implements SurfaceHolder.Callback{private static final String TAG = "PhotographSurface";private SurfaceHolder mSurfaceHolder;private Camera mCamera;public PhotographSurface(Context context) {super(context);init();}/** if you want to create a View in the layout, you have to implement the constructor with two parameters **/public PhotographSurface(Context context, AttributeSet attrs) {super(context, attrs);init();}public PhotographSurface(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);init();}private void init() {mSurfaceHolder = getHolder();mSurfaceHolder.addCallback(this);        //mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);}public void setCamera(Camera camera) {mCamera = camera;}@Overridepublic void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {// TODO Auto-generated method stub}@Overridepublic void surfaceCreated(SurfaceHolder arg0) {      try      {         if( mCamera != null )         {         mCamera.setPreviewDisplay( mSurfaceHolder );         }      }      catch( Exception exception )      {      Log.d( TAG, "SurfaceCreated failed" );      }}@Overridepublic void surfaceDestroyed(SurfaceHolder arg0) {// TODO Auto-generated method stub}}

6. SingleCamera.java:Camera的单例模式,这里我去掉了Camera在open时的回调,主要是因为,我原博主在回调的方法中就开始startPreview了,而我需要在这之间为创建的PhotographSurface对象传入Camera,并设置Holder,这样才能在PhotographSurface中正常的预览。

package org.hwm.app.photograph;import org.hwm.app.util.CamParaUtil;import org.hwm.app.util.FileUtil;import org.hwm.app.util.ImageUtil;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.ImageFormat;import android.hardware.Camera;import android.hardware.Camera.PictureCallback;import android.hardware.Camera.ShutterCallback;import android.util.Log;public class SingleCamera {private static final String TAG = "SingleCamera";private static SingleCamera cameraInstance;private Camera mCamera;private Camera.Parameters mCameraParams;private boolean isPreviewing = false;private SingleCamera(){};public static SingleCamera getInstance(){if (cameraInstance == null) {synchronized(SingleCamera.class) {cameraInstance = new SingleCamera();}}return cameraInstance;}public void doOpenCamera(){Log.i(TAG, "Camera open...");mCamera = Camera.open();}/** * start preview */public void doStartPreview(float previewRate){Log.i(TAG, "start preview...");if (isPreviewing) {mCamera.stopPreview();return;}if (mCamera != null) {// get Camera's parameters and reset itmCameraParams = mCamera.getParameters();mCameraParams.setPictureFormat(ImageFormat.JPEG);Camera.Size pictureSize = CamParaUtil.getInstance().getPropPictureSize(mCameraParams.getSupportedPictureSizes(), previewRate, 800); Camera.Size previewSize = CamParaUtil.getInstance().getPropPreviewSize(mCameraParams.getSupportedPreviewSizes(), previewRate, 800);mCameraParams.setPictureSize(pictureSize.width, pictureSize.height);mCameraParams.setPreviewSize(previewSize.width, previewSize.height);mCamera.setParameters(mCameraParams);// set display orientationmCamera.setDisplayOrientation(90);// start previewmCamera.startPreview();isPreviewing = true;}}/** * stop preview, and release Camera that other app can use it */public void doStopCamera() {if (mCamera != null) {mCamera.setPreviewCallback(null);mCamera.stopPreview();isPreviewing = false;mCamera.release();mCamera = null;}}/** * photoghraph */public void doTakePicture() {if (isPreviewing && (mCamera != null)) {mCamera.takePicture(mShutterCallback, mPictureCallback, mJpegPictureCallback);}}// the callback for image capture moment, or nullShutterCallback mShutterCallback = new ShutterCallback() {@Overridepublic void onShutter() {Log.i(TAG, "ShutterCallback...");}};// the callback for raw (uncompressed) image data, or nullPictureCallback mPictureCallback = new PictureCallback() {@Overridepublic void onPictureTaken(byte[] arg0, Camera arg1) {Log.i(TAG, "PictureCallback...");}};// the callback for JPEG image data. set the path to save picturePictureCallback mJpegPictureCallback = new PictureCallback() {@Overridepublic void onPictureTaken(byte[] data, Camera camera) {Log.i(TAG, "JpegPictureCallback...");Bitmap b = null;// to take a picture, we have to stop previewif (null != data) {b = BitmapFactory.decodeByteArray(data, 0, data.length);mCamera.stopPreview();isPreviewing = false;}// save the picture to sdcardif (null != b) {Bitmap rotateBitmap = ImageUtil.getRotateBitmap(b, 90f);FileUtil.saveBitmap(rotateBitmap);}// after saving picture, start previewmCamera.startPreview();isPreviewing = true;}};public Camera getCamera() {return this.mCamera;}}

7. PhotographActivity.java:在我的Activity中,大家可以看到我在执行doOpenCamera()和doStartPreview()方法之间,为SurfaceView传入了Camera。

package org.hwm.app.photograph;import org.hwm.app.util.DisplayUtil;import android.app.Activity;import android.graphics.Point;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.view.ViewGroup.LayoutParams;import android.widget.ImageButton;public class PhotographActivity extends Activity {private PhotographSurface mCameraSurface;private ImageButton btn_shutter;private float previewRate = -1f;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_photograph);        initView();        initParams();        btn_shutter.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_shutter :SingleCamera.getInstance().doTakePicture();break;default :break;}}        });    }private void initView() {        mCameraSurface = (PhotographSurface) findViewById(R.id.surfaceview);        btn_shutter = (ImageButton) findViewById(R.id.btn_shutter);}    private void initParams() {        LayoutParams params = mCameraSurface.getLayoutParams();          Point p = DisplayUtil.getScreenMetrics(this);          params.width = p.x;          params.height = p.y;          previewRate = DisplayUtil.getScreenRate(this);         mCameraSurface.setLayoutParams(params);                  LayoutParams p2 = btn_shutter.getLayoutParams();          p2.width = DisplayUtil.dip2px(this, 80);          p2.height = DisplayUtil.dip2px(this, 80);;                btn_shutter.setLayoutParams(p2);     }@Override    public void onResume() {    super.onResume();    SingleCamera.getInstance().doOpenCamera();    mCameraSurface.setCamera(SingleCamera.getInstance().getCamera());    SingleCamera.getInstance().doStartPreview(previewRate);    }}

        总之,实现Camera的拍照也是很简单的,但最好还是先看一下官方API给的流程。而对于原博主的代码,我不知道为什么原博主可以正常预览,而我的不行,所以在这里做了这些修改,以供以后查阅使用!

0 0
原创粉丝点击