玩转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(this80);  
  64.         p2.height = DisplayUtil.dip2px(this80);;        
  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, 00, 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

百度云盘:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值