玩轉Android Camera開發(一):Surfaceview預覽Camera,基礎拍照功能完整demo


雜家前文是在2012年的除夕之夜倉促完成,后來很多人指出了一些問題,瑣事纏身一直沒有進行升級。后來隨着我自己的使用,越來越發現不出個升級版的demo是不行了。有時候就連我自己用這個demo測一些性能、功能點,用着都不順手。當初代碼是在linux下寫的,弄到windows里下全是亂碼。還要自己改幾分鍾才能改好。另外,很多人說不能正常預覽,原因是我在布局里把Surfaceview的尺寸寫死了。再有就是initCamera()的時候設參數失敗,直接黑屏退出,原因也是我把預覽尺寸和照片尺寸寫死了。再有就是照片變形的問題。為此,今天出一個升級版的demo,爭取全面適配所有機型。

上圖為此次的代碼結構,activity包里就是放CameraActivity,日后添加圖庫瀏覽功能再加GalleryActivity。為了使Camera的邏輯和界面的UI耦合度降至最低,封裝了CameraInterface類,里面操作Camera的打開、預覽、拍照、關閉。preview包里是自定義的Surfaceview。在util包里放着CamParaUtil是專門用來設置、打印Camera的PreviewSize、PictureSize、FocusMode的,並能根據Activity傳進來的長寬比(主要是16:9 或 4:3兩種尺寸)自動尋找適配的PreviewSize和PictureSize,消除變形。默認的是全屏,因為一些手機全屏時,屏幕的長寬比不是16:9或4:3所以在找尺寸時也是存在一些偏差的。其中有個值,就是判斷兩個float是否相等,這個參數比較關鍵,里面設的0.03.經我多個手機測試,這個參數是最合適的,否則的話有些奇葩手機得到的尺寸拍出照片變形。下面上源碼:

一、布局 activity_camera.xml

 

[html]  view plain  copy
 
 print?在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-family:Comic Sans MS;font-size:18px;"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     tools:context=".CameraActivity" >  
  6.     <FrameLayout  
  7.         android:layout_width="wrap_content"  
  8.         android:layout_height="wrap_content" >  
  9.   
  10.         <org.yanzi.camera.preview.CameraSurfaceView  
  11.             android:id="@+id/camera_surfaceview"  
  12.             android:layout_width="0dip"  
  13.             android:layout_height="0dip" />  
  14.     </FrameLayout>  
  15.   
  16.     <ImageButton  
  17.         android:id="@+id/btn_shutter"  
  18.         android:layout_width="wrap_content"  
  19.         android:layout_height="wrap_content"  
  20.         android:background="@drawable/btn_shutter_background"  
  21.         android:layout_alignParentBottom="true"  
  22.         android:layout_centerHorizontal="true"   
  23.         android:layout_marginBottom="10dip"/>  
  24.   
  25.   
  26. </RelativeLayout>  
  27. </span>  


二、AndroidManifest.xml

 

 

[html]  view plain  copy
 
 print?在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-family:Comic Sans MS;font-size:18px;"><?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="org.yanzi.playcamera"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.   
  7.     <uses-sdk  
  8.         android:minSdkVersion="9"  
  9.         android:targetSdkVersion="17" />  
  10.         <!-- 增加文件存儲和訪問攝像頭的權限 -->  
  11.     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />  
  12.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
  13.     <uses-permission android:name="android.permission.CAMERA" />  
  14.     <uses-feature android:name="android.hardware.camera" />  
  15.   
  16.     <application  
  17.         android:allowBackup="true"  
  18.         android:icon="@drawable/ic_launcher_icon"  
  19.         android:label="@string/app_name"  
  20.         android:theme="@style/AppTheme" >  
  21.         <activity  
  22.             android:name="org.yanzi.activity.CameraActivity"  
  23.             android:label="@string/app_name"   
  24.             android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"  
  25.             android:screenOrientation="portrait">  
  26.             <intent-filter>  
  27.                 <action android:name="android.intent.action.MAIN" />  
  28.   
  29.                 <category android:name="android.intent.category.LAUNCHER" />  
  30.             </intent-filter>  
  31.         </activity>  
  32.     </application>  
  33.   
  34. </manifest>  
  35. </span>  


三、下面是java代碼

 

1、CameraActivity.Java

 

[java]  view plain  copy
 
 print?在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.activity;  
  2.   
  3. import org.yanzi.camera.CameraInterface;  
  4. import org.yanzi.camera.CameraInterface.CamOpenOverCallback;  
  5. import org.yanzi.camera.preview.CameraSurfaceView;  
  6. import org.yanzi.playcamera.R;  
  7. import org.yanzi.util.DisplayUtil;  
  8.   
  9. import android.app.Activity;  
  10. import android.graphics.Point;  
  11. import android.os.Bundle;  
  12. import android.view.Menu;  
  13. import android.view.SurfaceHolder;  
  14. import android.view.View;  
  15. import android.view.View.OnClickListener;  
  16. import android.view.ViewGroup.LayoutParams;  
  17. import android.widget.ImageButton;  
  18.   
  19. public class CameraActivity extends Activity implements CamOpenOverCallback {  
  20.     private static final String TAG = "yanzi";  
  21.     CameraSurfaceView surfaceView = null;  
  22.     ImageButton shutterBtn;  
  23.     float previewRate = -1f;  
  24.     @Override  
  25.     protected void onCreate(Bundle savedInstanceState) {  
  26.         super.onCreate(savedInstanceState);  
  27.         Thread openThread = new Thread(){  
  28.             @Override  
  29.             public void run() {  
  30.                 // TODO Auto-generated method stub  
  31.                 CameraInterface.getInstance().doOpenCamera(CameraActivity.this);  
  32.             }  
  33.         };  
  34.         openThread.start();  
  35.         setContentView(R.layout.activity_camera);  
  36.         initUI();  
  37.         initViewParams();  
  38.           
  39.         shutterBtn.setOnClickListener(new BtnListeners());  
  40.     }  
  41.   
  42.     @Override  
  43.     public boolean onCreateOptionsMenu(Menu menu) {  
  44.         // Inflate the menu; this adds items to the action bar if it is present.  
  45.         getMenuInflater().inflate(R.menu.camera, menu);  
  46.         return true;  
  47.     }  
  48.   
  49.     private void initUI(){  
  50.         surfaceView = (CameraSurfaceView)findViewById(R.id.camera_surfaceview);  
  51.         shutterBtn = (ImageButton)findViewById(R.id.btn_shutter);  
  52.     }  
  53.     private void initViewParams(){  
  54.         LayoutParams params = surfaceView.getLayoutParams();  
  55.         Point p = DisplayUtil.getScreenMetrics(this);  
  56.         params.width = p.x;  
  57.         params.height = p.y;  
  58.         previewRate = DisplayUtil.getScreenRate(this); //默認全屏的比例預覽  
  59.         surfaceView.setLayoutParams(params);  
  60.   
  61.         //手動設置拍照ImageButton的大小為120dip×120dip,原圖片大小是64×64  
  62.         LayoutParams p2 = shutterBtn.getLayoutParams();  
  63.         p2.width = DisplayUtil.dip2px(this, 80);  
  64.         p2.height = DisplayUtil.dip2px(this, 80);;        
  65.         shutterBtn.setLayoutParams(p2);   
  66.   
  67.     }  
  68.   
  69.     @Override  
  70.     public void cameraHasOpened() {  
  71.         // TODO Auto-generated method stub  
  72.         SurfaceHolder holder = surfaceView.getSurfaceHolder();  
  73.         CameraInterface.getInstance().doStartPreview(holder, previewRate);  
  74.     }  
  75.     private class BtnListeners implements OnClickListener{  
  76.   
  77.         @Override  
  78.         public void onClick(View v) {  
  79.             // TODO Auto-generated method stub  
  80.             switch(v.getId()){  
  81.             case R.id.btn_shutter:  
  82.                 CameraInterface.getInstance().doTakePicture();  
  83.                 break;  
  84.             default:break;  
  85.             }  
  86.         }  
  87.   
  88.     }  
  89.   
  90. }  
  91. </span>  


2、CameraInterface.java

 

 

[java]  view plain  copy
 
 print?在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.camera;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.List;  
  5.   
  6. import org.yanzi.util.CamParaUtil;  
  7. import org.yanzi.util.FileUtil;  
  8. import org.yanzi.util.ImageUtil;  
  9.   
  10. import android.graphics.Bitmap;  
  11. import android.graphics.BitmapFactory;  
  12. import android.graphics.PixelFormat;  
  13. import android.hardware.Camera;  
  14. import android.hardware.Camera.PictureCallback;  
  15. import android.hardware.Camera.ShutterCallback;  
  16. import android.hardware.Camera.Size;  
  17. import android.util.Log;  
  18. import android.view.SurfaceHolder;  
  19.   
  20. public class CameraInterface {  
  21.     private static final String TAG = "yanzi";  
  22.     private Camera mCamera;  
  23.     private Camera.Parameters mParams;  
  24.     private boolean isPreviewing = false;  
  25.     private float mPreviwRate = -1f;  
  26.     private static CameraInterface mCameraInterface;  
  27.   
  28.     public interface CamOpenOverCallback{  
  29.         public void cameraHasOpened();  
  30.     }  
  31.   
  32.     private CameraInterface(){  
  33.   
  34.     }  
  35.     public static synchronized CameraInterface getInstance(){  
  36.         if(mCameraInterface == null){  
  37.             mCameraInterface = new CameraInterface();  
  38.         }  
  39.         return mCameraInterface;  
  40.     }  
  41.     /**打開Camera 
  42.      * @param callback 
  43.      */  
  44.     public void doOpenCamera(CamOpenOverCallback callback){  
  45.         Log.i(TAG, "Camera open....");  
  46.         mCamera = Camera.open();  
  47.         Log.i(TAG, "Camera open over....");  
  48.         callback.cameraHasOpened();  
  49.     }  
  50.     /**開啟預覽 
  51.      * @param holder 
  52.      * @param previewRate 
  53.      */  
  54.     public void doStartPreview(SurfaceHolder holder, float previewRate){  
  55.         Log.i(TAG, "doStartPreview...");  
  56.         if(isPreviewing){  
  57.             mCamera.stopPreview();  
  58.             return;  
  59.         }  
  60.         if(mCamera != null){  
  61.   
  62.             mParams = mCamera.getParameters();  
  63.             mParams.setPictureFormat(PixelFormat.JPEG);//設置拍照后存儲的圖片格式  
  64.             CamParaUtil.getInstance().printSupportPictureSize(mParams);  
  65.             CamParaUtil.getInstance().printSupportPreviewSize(mParams);  
  66.             //設置PreviewSize和PictureSize  
  67.             Size pictureSize = CamParaUtil.getInstance().getPropPictureSize(  
  68.                     mParams.getSupportedPictureSizes(),previewRate, 800);  
  69.             mParams.setPictureSize(pictureSize.width, pictureSize.height);  
  70.             Size previewSize = CamParaUtil.getInstance().getPropPreviewSize(  
  71.                     mParams.getSupportedPreviewSizes(), previewRate, 800);  
  72.             mParams.setPreviewSize(previewSize.width, previewSize.height);  
  73.   
  74.             mCamera.setDisplayOrientation(90);  
  75.   
  76.             CamParaUtil.getInstance().printSupportFocusMode(mParams);  
  77.             List<String> focusModes = mParams.getSupportedFocusModes();  
  78.             if(focusModes.contains("continuous-video")){  
  79.                 mParams.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);  
  80.             }  
  81.             mCamera.setParameters(mParams);   
  82.   
  83.             try {  
  84.                 mCamera.setPreviewDisplay(holder);  
  85.                 mCamera.startPreview();//開啟預覽  
  86.             } catch (IOException e) {  
  87.                 // TODO Auto-generated catch block  
  88.                 e.printStackTrace();  
  89.             }  
  90.   
  91.             isPreviewing = true;  
  92.             mPreviwRate = previewRate;  
  93.   
  94.             mParams = mCamera.getParameters(); //重新get一次  
  95.             Log.i(TAG, "最終設置:PreviewSize--With = " + mParams.getPreviewSize().width  
  96.                     + "Height = " + mParams.getPreviewSize().height);  
  97.             Log.i(TAG, "最終設置:PictureSize--With = " + mParams.getPictureSize().width  
  98.                     + "Height = " + mParams.getPictureSize().height);  
  99.         }  
  100.     }  
  101.     /** 
  102.      * 停止預覽,釋放Camera 
  103.      */  
  104.     public void doStopCamera(){  
  105.         if(null != mCamera)  
  106.         {  
  107.             mCamera.setPreviewCallback(null);  
  108.             mCamera.stopPreview();   
  109.             isPreviewing = false;   
  110.             mPreviwRate = -1f;  
  111.             mCamera.release();  
  112.             mCamera = null;       
  113.         }  
  114.     }  
  115.     /** 
  116.      * 拍照 
  117.      */  
  118.     public void doTakePicture(){  
  119.         if(isPreviewing && (mCamera != null)){  
  120.             mCamera.takePicture(mShutterCallback, null, mJpegPictureCallback);  
  121.         }  
  122.     }  
  123.   
  124.     /*為了實現拍照的快門聲音及拍照保存照片需要下面三個回調變量*/  
  125.     ShutterCallback mShutterCallback = new ShutterCallback()   
  126.     //快門按下的回調,在這里我們可以設置類似播放“咔嚓”聲之類的操作。默認的就是咔嚓。  
  127.     {  
  128.         public void onShutter() {  
  129.             // TODO Auto-generated method stub  
  130.             Log.i(TAG, "myShutterCallback:onShutter...");  
  131.         }  
  132.     };  
  133.     PictureCallback mRawCallback = new PictureCallback()   
  134.     // 拍攝的未壓縮原數據的回調,可以為null  
  135.     {  
  136.   
  137.         public void onPictureTaken(byte[] data, Camera camera) {  
  138.             // TODO Auto-generated method stub  
  139.             Log.i(TAG, "myRawCallback:onPictureTaken...");  
  140.   
  141.         }  
  142.     };  
  143.     PictureCallback mJpegPictureCallback = new PictureCallback()   
  144.     //對jpeg圖像數據的回調,最重要的一個回調  
  145.     {  
  146.         public void onPictureTaken(byte[] data, Camera camera) {  
  147.             // TODO Auto-generated method stub  
  148.             Log.i(TAG, "myJpegCallback:onPictureTaken...");  
  149.             Bitmap b = null;  
  150.             if(null != data){  
  151.                 b = BitmapFactory.decodeByteArray(data, 0, data.length);//data是字節數據,將其解析成位圖  
  152.                 mCamera.stopPreview();  
  153.                 isPreviewing = false;  
  154.             }  
  155.             //保存圖片到sdcard  
  156.             if(null != b)  
  157.             {  
  158.                 //設置FOCUS_MODE_CONTINUOUS_VIDEO)之后,myParam.set("rotation", 90)失效。  
  159.                 //圖片竟然不能旋轉了,故這里要旋轉下  
  160.                 Bitmap rotaBitmap = ImageUtil.getRotateBitmap(b, 90.0f);  
  161.                 FileUtil.saveBitmap(rotaBitmap);  
  162.             }  
  163.             //再次進入預覽  
  164.             mCamera.startPreview();  
  165.             isPreviewing = true;  
  166.         }  
  167.     };  
  168.   
  169.   
  170. }  
  171. </span>  


3、CameraSurfaceView.java

 

 

[java]  view plain  copy
 
 print?在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.camera.preview;  
  2.   
  3. import org.yanzi.camera.CameraInterface;  
  4.   
  5. import android.content.Context;  
  6. import android.graphics.PixelFormat;  
  7. import android.util.AttributeSet;  
  8. import android.util.Log;  
  9. import android.view.SurfaceHolder;  
  10. import android.view.SurfaceView;  
  11.   
  12. public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {  
  13.     private static final String TAG = "yanzi";  
  14.     CameraInterface mCameraInterface;  
  15.     Context mContext;  
  16.     SurfaceHolder mSurfaceHolder;  
  17.     public CameraSurfaceView(Context context, AttributeSet attrs) {  
  18.         super(context, attrs);  
  19.         // TODO Auto-generated constructor stub  
  20.         mContext = context;  
  21.         mSurfaceHolder = getHolder();  
  22.         mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);//translucent半透明 transparent透明  
  23.         mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  
  24.         mSurfaceHolder.addCallback(this);  
  25.     }  
  26.   
  27.     @Override  
  28.     public void surfaceCreated(SurfaceHolder holder) {  
  29.         // TODO Auto-generated method stub  
  30.         Log.i(TAG, "surfaceCreated...");  
  31.     }  
  32.   
  33.     @Override  
  34.     public void surfaceChanged(SurfaceHolder holder, int format, int width,  
  35.             int height) {  
  36.         // TODO Auto-generated method stub  
  37.         Log.i(TAG, "surfaceChanged...");  
  38.     }  
  39.   
  40.     @Override  
  41.     public void surfaceDestroyed(SurfaceHolder holder) {  
  42.         // TODO Auto-generated method stub  
  43.         Log.i(TAG, "surfaceDestroyed...");  
  44.         CameraInterface.getInstance().doStopCamera();  
  45.     }  
  46.     public SurfaceHolder getSurfaceHolder(){  
  47.         return mSurfaceHolder;  
  48.     }  
  49.       
  50. }  
  51. </span>  


4、CamParaUtil.java

 

 

[java]  view plain  copy
 
 print?在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.util;  
  2.   
  3. import java.util.Collections;  
  4. import java.util.Comparator;  
  5. import java.util.List;  
  6.   
  7. import android.hardware.Camera;  
  8. import android.hardware.Camera.Size;  
  9. import android.util.Log;  
  10.   
  11. public class CamParaUtil {  
  12.     private static final String TAG = "yanzi";  
  13.     private CameraSizeComparator sizeComparator = new CameraSizeComparator();  
  14.     private static CamParaUtil myCamPara = null;  
  15.     private CamParaUtil(){  
  16.   
  17.     }  
  18.     public static CamParaUtil getInstance(){  
  19.         if(myCamPara == null){  
  20.             myCamPara = new CamParaUtil();  
  21.             return myCamPara;  
  22.         }  
  23.         else{  
  24.             return myCamPara;  
  25.         }  
  26.     }  
  27.   
  28.     public  Size getPropPreviewSize(List<Camera.Size> list, float th, int minWidth){  
  29.         Collections.sort(list, sizeComparator);  
  30.   
  31.         int i = 0;  
  32.         for(Size s:list){  
  33.             if((s.width >= minWidth) && equalRate(s, th)){  
  34.                 Log.i(TAG, "PreviewSize:w = " + s.width + "h = " + s.height);  
  35.                 break;  
  36.             }  
  37.             i++;  
  38.         }  
  39.         if(i == list.size()){  
  40.             i = 0;//如果沒找到,就選最小的size  
  41.         }  
  42.         return list.get(i);  
  43.     }  
  44.     public Size getPropPictureSize(List<Camera.Size> list, float th, int minWidth){  
  45.         Collections.sort(list, sizeComparator);  
  46.   
  47.         int i = 0;  
  48.         for(Size s:list){  
  49.             if((s.width >= minWidth) && equalRate(s, th)){  
  50.                 Log.i(TAG, "PictureSize : w = " + s.width + "h = " + s.height);  
  51.                 break;  
  52.             }  
  53.             i++;  
  54.         }  
  55.         if(i == list.size()){  
  56.             i = 0;//如果沒找到,就選最小的size  
  57.         }  
  58.         return list.get(i);  
  59.     }  
  60.   
  61.     public boolean equalRate(Size s, float rate){  
  62.         float r = (float)(s.width)/(float)(s.height);  
  63.         if(Math.abs(r - rate) <= 0.03)  
  64.         {  
  65.             return true;  
  66.         }  
  67.         else{  
  68.             return false;  
  69.         }  
  70.     }  
  71.   
  72.     public  class CameraSizeComparator implements Comparator<Camera.Size>{  
  73.         public int compare(Size lhs, Size rhs) {  
  74.             // TODO Auto-generated method stub  
  75.             if(lhs.width == rhs.width){  
  76.                 return 0;  
  77.             }  
  78.             else if(lhs.width > rhs.width){  
  79.                 return 1;  
  80.             }  
  81.             else{  
  82.                 return -1;  
  83.             }  
  84.         }  
  85.   
  86.     }  
  87.   
  88.     /**打印支持的previewSizes 
  89.      * @param params 
  90.      */  
  91.     public  void printSupportPreviewSize(Camera.Parameters params){  
  92.         List<Size> previewSizes = params.getSupportedPreviewSizes();  
  93.         for(int i=0; i< previewSizes.size(); i++){  
  94.             Size size = previewSizes.get(i);  
  95.             Log.i(TAG, "previewSizes:width = "+size.width+" height = "+size.height);  
  96.         }  
  97.       
  98.     }  
  99.   
  100.     /**打印支持的pictureSizes 
  101.      * @param params 
  102.      */  
  103.     public  void printSupportPictureSize(Camera.Parameters params){  
  104.         List<Size> pictureSizes = params.getSupportedPictureSizes();  
  105.         for(int i=0; i< pictureSizes.size(); i++){  
  106.             Size size = pictureSizes.get(i);  
  107.             Log.i(TAG, "pictureSizes:width = "+ size.width  
  108.                     +" height = " + size.height);  
  109.         }  
  110.     }  
  111.     /**打印支持的聚焦模式 
  112.      * @param params 
  113.      */  
  114.     public void printSupportFocusMode(Camera.Parameters params){  
  115.         List<String> focusModes = params.getSupportedFocusModes();  
  116.         for(String mode : focusModes){  
  117.             Log.i(TAG, "focusModes--" + mode);  
  118.         }  
  119.     }  
  120. }  
  121. </span>  


5、DisplayUtil.java

 

 

[java]  view plain  copy
 
 print?在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.util;  
  2.   
  3. import android.content.Context;  
  4. import android.graphics.Point;  
  5. import android.util.DisplayMetrics;  
  6. import android.util.Log;  
  7.   
  8. public class DisplayUtil {  
  9.     private static final String TAG = "DisplayUtil";  
  10.     /** 
  11.      * dip轉px 
  12.      * @param context 
  13.      * @param dipValue 
  14.      * @return 
  15.      */  
  16.     public static int dip2px(Context context, float dipValue){              
  17.         final float scale = context.getResources().getDisplayMetrics().density;                   
  18.         return (int)(dipValue * scale + 0.5f);           
  19.     }       
  20.       
  21.     /** 
  22.      * px轉dip 
  23.      * @param context 
  24.      * @param pxValue 
  25.      * @return 
  26.      */  
  27.     public static int px2dip(Context context, float pxValue){                  
  28.         final float scale = context.getResources().getDisplayMetrics().density;                   
  29.         return (int)(pxValue / scale + 0.5f);           
  30.     }   
  31.       
  32.     /** 
  33.      * 獲取屏幕寬度和高度,單位為px 
  34.      * @param context 
  35.      * @return 
  36.      */  
  37.     public static Point getScreenMetrics(Context context){  
  38.         DisplayMetrics dm =context.getResources().getDisplayMetrics();  
  39.         int w_screen = dm.widthPixels;  
  40.         int h_screen = dm.heightPixels;  
  41.         Log.i(TAG, "Screen---Width = " + w_screen + " Height = " + h_screen + " densityDpi = " + dm.densityDpi);  
  42.         return new Point(w_screen, h_screen);  
  43.           
  44.     }  
  45.       
  46.     /** 
  47.      * 獲取屏幕長寬比 
  48.      * @param context 
  49.      * @return 
  50.      */  
  51.     public static float getScreenRate(Context context){  
  52.         Point P = getScreenMetrics(context);  
  53.         float H = P.y;  
  54.         float W = P.x;  
  55.         return (H/W);  
  56.     }  
  57. }  
  58. </span>  


6、FileUtil.java

 

 

[java]  view plain  copy
 
 print?在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.util;  
  2.   
  3. import java.io.BufferedOutputStream;  
  4. import java.io.File;  
  5. import java.io.FileOutputStream;  
  6. import java.io.IOException;  
  7.   
  8. import android.graphics.Bitmap;  
  9. import android.os.Environment;  
  10. import android.util.Log;  
  11.   
  12. public class FileUtil {  
  13.     private static final  String TAG = "FileUtil";  
  14.     private static final File parentPath = Environment.getExternalStorageDirectory();  
  15.     private static   String storagePath = "";  
  16.     private static final String DST_FOLDER_NAME = "PlayCamera";  
  17.   
  18.     /**初始化保存路徑 
  19.      * @return 
  20.      */  
  21.     private static String initPath(){  
  22.         if(storagePath.equals("")){  
  23.             storagePath = parentPath.getAbsolutePath()+"/" + DST_FOLDER_NAME;  
  24.             File f = new File(storagePath);  
  25.             if(!f.exists()){  
  26.                 f.mkdir();  
  27.             }  
  28.         }  
  29.         return storagePath;  
  30.     }  
  31.   
  32.     /**保存Bitmap到sdcard 
  33.      * @param b 
  34.      */  
  35.     public static void saveBitmap(Bitmap b){  
  36.   
  37.         String path = initPath();  
  38.         long dataTake = System.currentTimeMillis();  
  39.         String jpegName = path + "/" + dataTake +".jpg";  
  40.         Log.i(TAG, "saveBitmap:jpegName = " + jpegName);  
  41.         try {  
  42.             FileOutputStream fout = new FileOutputStream(jpegName);  
  43.             BufferedOutputStream bos = new BufferedOutputStream(fout);  
  44.             b.compress(Bitmap.CompressFormat.JPEG, 100, bos);  
  45.             bos.flush();  
  46.             bos.close();  
  47.             Log.i(TAG, "saveBitmap成功");  
  48.         } catch (IOException e) {  
  49.             // TODO Auto-generated catch block  
  50.             Log.i(TAG, "saveBitmap:失敗");  
  51.             e.printStackTrace();  
  52.         }  
  53.   
  54.     }  
  55.   
  56.   
  57. }  
  58. </span>  


7、ImageUtil.java

 

 

[java]  view plain  copy
 
 print?在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.util;  
  2.   
  3. import android.graphics.Bitmap;  
  4. import android.graphics.Matrix;  
  5.   
  6. public class ImageUtil {  
  7.     /** 
  8.      * 旋轉Bitmap 
  9.      * @param b 
  10.      * @param rotateDegree 
  11.      * @return 
  12.      */  
  13.     public static Bitmap getRotateBitmap(Bitmap b, float rotateDegree){  
  14.         Matrix matrix = new Matrix();  
  15.         matrix.postRotate((float)rotateDegree);  
  16.         Bitmap rotaBitmap = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), matrix, false);  
  17.         return rotaBitmap;  
  18.     }  
  19. }  
  20. </span>  


幾點說明:

 

1、包括我之前的博文在內的大量網上鏈接,都是在Surfaceview create的時候進行打開Camera的操作,在Surfaceview Changed的時候進行開預覽。而Surfaceview create的時候一定是在setContentView之后,Surfaceview實例化之后。為了優化開啟Camera時間,我再setContentView之前new了一個線程專門去Open Camera。經過測試,但就執行Camera.open()這句話一般需要140ms左右。如果放在主線程里無疑是一種浪費。而在140ms之后,Surfaceview里因為無需觸發關於Camera的操作,所以加載的特別快。也就是說Open完后,Surfaceview一定完成了實例化。所以我設置了CamOpenOverCallback回調,在Camera打開完畢后通知Activity立即執行開預覽的操作。

2、開預覽因為用Surfaceview預覽,需傳遞Surfaceview的SurfaceHolder。

3、CameraInterface是個單例模式,所有關於Camera的流程性操作一律封裝在這里面。

4、Activity設置了全屏無標題且強制豎屏,像這種操作能再xml寫就不要再java代碼里弄。

圖片資源上,雜家還真是一番精心挑選,對比了Camera360、相機360、美顏相機,UI上總的來說三個app感覺都很垃圾,都整的太復雜了,圖片也不好看。最后勉強用了相機360里的一個button,自己想用PS把按鍵點擊時的圖標色彩P亮點,一個沒留神,還給P的更暗了色彩。汗,不過按鍵的對比效果更明顯了。日后,會將一些OpenCV4Android的一些小demo都整合到PlayCamera系列。

下為效果圖:

------------本文系原創,轉載請注明作者yanzi1225627

版本號:PlayCamera_V1.0.0[2014-6-22].zip

CSDN下載鏈接:http://download.csdn.net/detail/yanzi1225627/7540873

百度雲盤:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM