Android Camera拍照实现

        既然都已经学了如何打开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;
	}

	@Override
	public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
		// TODO Auto-generated method stub
	}

	@Override
	public void surfaceCreated(SurfaceHolder arg0) {
	      try
	      {
	         if( mCamera != null )
	         {
	        	 mCamera.setPreviewDisplay( mSurfaceHolder );
	         }
	      }
	      catch( Exception exception )
	      {
		      Log.d( TAG, "SurfaceCreated failed" );
	      }
	}

	@Override
	public 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 it
			mCameraParams = 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 orientation
			mCamera.setDisplayOrientation(90);
			// start preview
			mCamera.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 null
	ShutterCallback mShutterCallback = new ShutterCallback() {
		@Override
		public void onShutter() {
			Log.i(TAG, "ShutterCallback...");
		}
	};
	
	// the callback for raw (uncompressed) image data, or null
	PictureCallback mPictureCallback = new PictureCallback() {
		@Override
		public void onPictureTaken(byte[] arg0, Camera arg1) {
			Log.i(TAG, "PictureCallback...");
		}
	};
	
	// the callback for JPEG image data. set the path to save picture
	PictureCallback mJpegPictureCallback = new PictureCallback() {
		@Override
		public void onPictureTaken(byte[] data, Camera camera) {
			Log.i(TAG, "JpegPictureCallback...");
			Bitmap b = null;
			// to take a picture, we have to stop preview
			if (null != data) {
				b = BitmapFactory.decodeByteArray(data, 0, data.length);
				mCamera.stopPreview();
				isPreviewing = false;
			}
			// save the picture to sdcard
			if (null != b) {
				Bitmap rotateBitmap = ImageUtil.getRotateBitmap(b, 90f);
				FileUtil.saveBitmap(rotateBitmap);
			}
			// after saving picture, start preview
			mCamera.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() {
			@Override
			public 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给的流程。而对于原博主的代码,我不知道为什么原博主可以正常预览,而我的不行,所以在这里做了这些修改,以供以后查阅使用!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值