老规矩,先上一下项目地址:GitHub:​​https://github.com/xiangzhihong/CameraDemo​

方式:

  • 调用Camera API 自定义相机
  • 调用系统相机

由于需求不同,所以选择的方案固然也不同,至于第二种调用系统相机,这里就不过多讲解了,使用Intent对象设置一个Action动作即可,跳转时使用startActivityForResult,然后在onActivityResult处理相关数据便可,关键代码:


[java]  ​​view plain​​  ​​copy​​


 ​​print​

​​?​



  1. intent.setAction("android.media.action.STILL_IMAGE_CAMERA");  


至于使用,较常见的一般是应用中用户上传头像的时候调用,然后返回处理图像数据。


而第一种自定义相机的方式使用也十分普遍,但是要做好这个模块,相对来说还是有一定难度的,之前分享过一个Github上的开源相机的项目,项目由美国的一个团队开发,集 拍照、摄影、各种特效动画 等功能与一身,本人之前研究了下,发现功能比较全面也很强大,抠出来单独拍照那一个模块,我滴妈呀,真TM费劲!相机不管是预览还是拍摄图像都还是很清晰的,自己当时也写了一个,比较操蛋,只能怪自己对这一块的优化了解浅显吧!特别是预览的时候,聚焦完成后,焦点周边会出现很多白色的噪点,密密麻麻,特别严重,头疼的很。不过也总算解决了,灰常感谢USA的那个什么什么团队的开源相机程序。经过自己改造后的预览效果图:

android 自定义相机_整型

下面看下这个项目的效果图,我也把地址甩底下,大伙感兴趣的自行Clone研究(或者闲的蛋疼也可以抽时间剥离开每一个模块学习,作为日后的知识储备),里面也用到了这个​​Android中读取图片EXIF元数据之metadata-extractor的使用​​。

android 自定义相机_android_02



相机开发简介

下面说说在Android中调用Camera来定义相机的最基本步骤:

  1. 打开相机 —— 调用Camera的open()方法。
  2. 获取拍照参数 —— 调用Camera的getParameters()方法,返回Camera.Parameters对象。
  3. 拍照参数设置 —— 调用Camera.Parameters对象。
  4. 拍照参数控制 —— 调用Camera的setParameters(),并将Camera.Parameters对象作为参数传入。注:Android2.3.3之后不用设置。
  5. 预览取景 —— 调用Camera的startPreview()方法,在之前注意调用Camera的setPreviewDisplay(SurfaceHolder holder)设置使用哪个SurfaceView来显示取得的图片。
  6. 拍照 —— 调用Camera的takePicture()
  7. 停止预览 —— 调用Camera的stopPreview()方法
  8. 资源释放 —— Camera.release()

开启和关闭预览的联系如下:Camera ---- SurfaceHolder ------ SurfaceView

关于SurfaceHolder.Callback必须实现的3个方法:

surfaceCreated() 该方法在surfaceView被Create时调用
surfaceChanged() 该方法是当surfaceView发生改变后调用
surfaceDestroyed() 这个不用说了,销毁时调用

surfaceHolder通过addCallBack()方法将响应的接口绑定

注:必要Camera权限,例如:


[html]  ​​view plain​​  ​​copy​​


 ​​print​

​​?​



  1. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>  
  2.   
  3. <uses-permission android:name="android.permission.CAMERA"/>  
  4.   
  5. <uses-feature android:name="android.hardware.camera" />  
  6.   
  7. <uses-permission android:name="android.hardware.camera.autofocus" />  
  8.   
  9. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  




关于Camera下的Parameters类,其中封装了我们需要的大部分功能,下面做个简单介绍:

  1. setPictureFormat() 方法用于设置相机照片的格式,其参数是一个字符型参数,位于PixelFormat类中,如:PixelFormat.JPEG。
  2. setSceneMode() 方法用于设置相机场景类型,其参是是一个字符型参数,位于Parameters类中,以SCENE_MODE_开头。
  3. setZoom() 方法用于设置相机焦距,其参数是一个整型的参数,该参数的范围是0到Camera.getParameters().getMaxZoom()。
  4. setPictureSize() 方法用于设置相机照片的大小,参数为整型。
  5. setWhiteBalance() 方法用于设置相机照片白平衡,其参数是一个字符型,位于Parameters类中,以WHITE_BALANCE开头。
  6. setJpegQuality() 方法用于设置相机照片的质量,其参数是一个整型参数,取值范围为1到100。
  7. setFlashMode() 方法用于设置闪光灯的类型,其参数是一个字符型参数,位于Parameters类中,以FLASH_MODE_开头。
  8. setColorEffect() 方法用于设置照片颜色特效的类型,其参数是一个字符型参数,位于Parameters类中,以EFFECT_开头。

本程序模块效果图及示例


下面分享本篇Blog的示例相机模块,此功能模块并非上面开源项目中的剥离出来的,看下效果图咯:


android 自定义相机_整型_03

         

android 自定义相机_android_04


android 自定义相机_github_05

         

android 自定义相机_整型_06

效果看着还可以吧(不点赞也太不给面子了吧  - . - ),下面个出主界面的布局代码:



[html]  ​​view plain​​  ​​copy​​

 ​​print​​ ​​?​​

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3. android:id="@+id/layout"  
  4. android:layout_width="match_parent"  
  5. android:layout_height="match_parent" >  
  6.   
  7. <!-- 预览画布 -->  
  8. <SurfaceView  
  9. android:id="@+id/surfaceView"  
  10. android:layout_width="match_parent"  
  11. android:layout_height="match_parent" />  
  12.   
  13. <!-- 闪光灯、前置摄像头、后置摄像头、聚焦 -->  
  14.   
  15. <RelativeLayout  
  16. android:layout_width="match_parent"  
  17. android:layout_height="match_parent" >  
  18.   
  19. <org.gaochun.camera.CameraGrid  
  20. android:id="@+id/camera_grid"  
  21. android:layout_width="match_parent"  
  22. android:layout_height="match_parent"  
  23. android:layout_alignParentTop="true" />  
  24.   
  25. <View  
  26. android:id="@+id/focus_index"  
  27. android:layout_width="40dp"  
  28. android:layout_height="40dp"  
  29. android:background="@drawable/camera_focus"  
  30. android:visibility="invisible" />  
  31.   
  32. <ImageView  
  33. android:id="@+id/flash_view"  
  34. android:layout_width="wrap_content"  
  35. android:layout_height="wrap_content"  
  36. android:layout_alignParentLeft="true"  
  37. android:onClick="onClick"  
  38. android:padding="15dp"  
  39. android:scaleType="centerCrop"  
  40. android:src="@drawable/camera_flash_off" />  
  41.   
  42. <ImageView  
  43. android:id="@+id/camera_flip_view"  
  44. android:layout_width="wrap_content"  
  45. android:layout_height="wrap_content"  
  46. android:layout_alignParentRight="true"  
  47. android:onClick="onClick"  
  48. android:padding="15dp"  
  49. android:scaleType="centerCrop"  
  50. android:src="@drawable/camera_flip" />  
  51.   
  52. <!-- 底部按钮 -->  
  53.   
  54. <RelativeLayout  
  55. android:layout_width="fill_parent"  
  56. android:layout_height="70dp"  
  57. android:layout_alignParentBottom="true"  
  58. android:background="#a0000000"  
  59. android:padding="5dp" >  
  60.   
  61. <Button  
  62. android:id="@+id/search"  
  63. android:layout_width="wrap_content"  
  64. android:layout_height="wrap_content"  
  65. android:layout_marginLeft="30dp"  
  66. android:background="@null"  
  67. android:drawablePadding="3dp"  
  68. android:drawableTop="@drawable/ic_search_selector"  
  69. android:onClick="onClick"  
  70. android:text="搜图"  
  71. android:textColor="@drawable/row_selector_text" />  
  72.   
  73. <ImageView  
  74. android:id="@+id/action_button"  
  75. android:layout_width="wrap_content"  
  76. android:layout_height="wrap_content"  
  77. android:layout_centerInParent="true"  
  78. android:clickable="true"  
  79. android:onClick="onClick"  
  80. android:src="@drawable/btn_shutter_photo" />  
  81.   
  82. <Button  
  83. android:id="@+id/takephoto"  
  84. android:layout_width="wrap_content"  
  85. android:layout_height="wrap_content"  
  86. android:layout_alignParentRight="true"  
  87. android:layout_marginRight="30dp"  
  88. android:background="@null"  
  89. android:drawablePadding="3dp"  
  90. android:drawableTop="@drawable/ic_takephoto_selector"  
  91. android:onClick="onClick"  
  92. android:text="拍照"  
  93. android:textColor="@drawable/row_selector_text" />  
  94. </RelativeLayout>  
  95. </RelativeLayout>  
  96.   
  97. </FrameLayout>  




下面是核心模块 CameraPreview 类:


[java]  ​​view plain​​  ​​copy​​

 ​​print​​ ​​?​​

  1. public class CameraPreview extends ViewGroup implements SurfaceHolder.Callback, Camera.AutoFocusCallback {  
  2.   
  3. private SurfaceView mSurfaceView;  
  4. private SurfaceHolder mHolder;  
  5. private Size mPreviewSize;  
  6. private Size adapterSize;  
  7. //private List<Size> mSupportedPreviewSizes;  
  8. private Camera mCamera;  
  9. private boolean isSupportAutoFocus = false;  
  10. private Camera.Parameters parameters = null;  
  11. private Context mContext;  
  12. //private int mCurrentCameraId = 0;  
  13. private int screenWidth;  
  14. private int screenHeight;  
  15.   
  16.     CameraPreview(Context context, SurfaceView sv) {  
  17. super(context);  
  18.         mContext = context;  
  19.         mSurfaceView = sv;  
  20.         mHolder = mSurfaceView.getHolder();  
  21. this);  
  22.         mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  
  23. true);  
  24.         isSupportAutoFocus = context.getPackageManager().hasSystemFeature(  
  25.                 PackageManager.FEATURE_CAMERA_AUTOFOCUS);  
  26. new DisplayMetrics();  
  27.         ((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(dm);  
  28.         screenWidth = dm.widthPixels;  
  29.         screenHeight = dm.heightPixels;  
  30.     }  
  31.   
  32. public void setCamera(Camera camera) {  
  33.         mCamera = camera;  
  34.         initCamera();  
  35.     }  
  36.   
  37. public void initCamera() {  
  38. if (mCamera != null) {  
  39.             Camera.Parameters params = mCamera.getParameters();  
  40. //mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();  
  41.             requestLayout();  
  42. if (mPreviewSize == null) {  
  43.                 mPreviewSize = findBestPreviewResolution();  
  44.             }  
  45. if (adapterSize == null) {  
  46.                 adapterSize = findBestPictureResolution();  
  47.             }  
  48. if (adapterSize != null) {  
  49.                 params.setPictureSize(adapterSize.width, adapterSize.height);  
  50.             }  
  51. if (mPreviewSize != null) {  
  52.                 params.setPreviewSize(mPreviewSize.width, mPreviewSize.height);  
  53.             }  
  54.             params.setPictureFormat(PixelFormat.JPEG);  
  55.             List<String> focusModes = params.getSupportedFocusModes();  
  56. if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {  
  57. // set the focus mode  
  58.                 params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);  
  59. // set Camera parameters  
  60.                 mCamera.setParameters(params);  
  61.             }  
  62.             setDispaly(params, mCamera);  
  63. //setCameraDisplayOrientation((Activity) mContext, mCurrentCameraId, mCamera);  
  64.             mCamera.setParameters(params);  
  65.         }  
  66.     }  
  67.   
  68. //控制图像的正确显示方向  
  69. private void setDispaly(Camera.Parameters parameters, Camera camera) {  
  70. if (Build.VERSION.SDK_INT >= 8) {  
  71. 90);  
  72. else {  
  73. 90);  
  74.         }  
  75.     }  
  76.   
  77. //实现的图像的正确显示  
  78. private void setDisplayOrientation(Camera camera, int i) {  
  79.         Method downPolymorphic;  
  80. try {  
  81. "setDisplayOrientation",  
  82. new Class[]{int.class});  
  83. if (downPolymorphic != null) {  
  84. new Object[]{i});  
  85.             }  
  86. catch (Exception e) {  
  87.             e.printStackTrace();  
  88.         }  
  89.     }  
  90.   
  91. public static void setCameraDisplayOrientation(Activity activity,  
  92. int cameraId, android.hardware.Camera camera) {  
  93.         android.hardware.Camera.CameraInfo info =  
  94. new android.hardware.Camera.CameraInfo();  
  95.         android.hardware.Camera.getCameraInfo(cameraId, info);  
  96. int rotation = activity.getWindowManager().getDefaultDisplay()  
  97.                 .getRotation();  
  98. int degrees = 0;  
  99. switch (rotation) {  
  100. case Surface.ROTATION_0:  
  101. 0;  
  102. break;  
  103. case Surface.ROTATION_90:  
  104. 90;  
  105. break;  
  106. case Surface.ROTATION_180:  
  107. 180;  
  108. break;  
  109. case Surface.ROTATION_270:  
  110. 270;  
  111. break;  
  112.         }  
  113.   
  114. int result;  
  115. if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {  
  116. 360;  
  117. 360 - result) % 360;  // compensate the mirror  
  118. else {  // back-facing  
  119. 360) % 360;  
  120.         }  
  121.         camera.setDisplayOrientation(result);  
  122.     }  
  123.   
  124. @Override  
  125. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  126. final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);  
  127. final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);  
  128.         setMeasuredDimension(width, height);  
  129. //        if (mSupportedPreviewSizes != null) {  
  130. //             mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);  
  131. //        }  
  132.     }  
  133.   
  134. @Override  
  135. protected void onLayout(boolean changed, int l, int t, int r, int b) {  
  136. if (changed && getChildCount() > 0) {  
  137. final View child = getChildAt(0);  
  138.   
  139. final int width = r - l;  
  140. final int height = b - t;  
  141.   
  142. int previewWidth = width;  
  143. int previewHeight = height;  
  144. if (mPreviewSize != null) {  
  145.                 previewWidth = mPreviewSize.width;  
  146.                 previewHeight = mPreviewSize.height;  
  147.             }  
  148.   
  149. // Center the child SurfaceView within the parent.  
  150. if (width * previewHeight > height * previewWidth) {  
  151. final int scaledChildWidth = previewWidth * height / previewHeight;  
  152. 2, 0,  
  153. 2, height);  
  154. else {  
  155. final int scaledChildHeight = previewHeight * width / previewWidth;  
  156. 0, (height - scaledChildHeight) / 2,  
  157. 2);  
  158.             }  
  159.         }  
  160.     }  
  161.   
  162. public void surfaceCreated(SurfaceHolder holder) {  
  163. // The Surface has been created, acquire the camera and tell it where  
  164. // to draw.  
  165. try {  
  166. if (mCamera != null) {  
  167.                 mCamera.setPreviewDisplay(holder);  
  168.             }  
  169. catch (IOException e) {  
  170. if (null != mCamera) {  
  171.                 mCamera.release();  
  172. null;  
  173.   
  174.             }  
  175.             e.printStackTrace();  
  176.         }  
  177.     }  
  178.   
  179. public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {  
  180. if (holder.getSurface() == null) {  
  181. return;  
  182.         }  
  183. if (mCamera != null) {  
  184.             Camera.Parameters parameters = mCamera.getParameters();  
  185.             parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);  
  186.             mCamera.setParameters(parameters);  
  187. try {  
  188.                 mCamera.setPreviewDisplay(holder);  
  189. catch (IOException e) {  
  190.                 e.printStackTrace();  
  191.             }  
  192.             mCamera.startPreview();  
  193.             reAutoFocus();  
  194.         }  
  195.     }  
  196.   
  197. public void surfaceDestroyed(SurfaceHolder holder) {  
  198. // Surface will be destroyed when we return, so stop the preview.  
  199. if (mCamera != null) {  
  200.             mCamera.stopPreview();  
  201.         }  
  202.     }  
  203.   
  204. /**
  205.      * 最小预览界面的分辨率
  206.      */  
  207. private static final int MIN_PREVIEW_PIXELS = 480 * 320;  
  208. /**
  209.      * 最大宽高比差
  210.      */  
  211. private static final double MAX_ASPECT_DISTORTION = 0.15;  
  212.   
  213. /**
  214.      * 找出最适合的预览界面分辨率
  215.      *
  216.      * @return
  217.      */  
  218. private Camera.Size findBestPreviewResolution() {  
  219.         Camera.Parameters cameraParameters = mCamera.getParameters();  
  220.         Camera.Size defaultPreviewResolution = cameraParameters.getPreviewSize();  
  221.   
  222.         List<Camera.Size> rawSupportedSizes = cameraParameters.getSupportedPreviewSizes();  
  223. if (rawSupportedSizes == null) {  
  224. return defaultPreviewResolution;  
  225.         }  
  226.   
  227. // 按照分辨率从大到小排序  
  228. new ArrayList<Camera.Size>(rawSupportedSizes);  
  229. new Comparator<Size>() {  
  230. @Override  
  231. public int compare(Camera.Size a, Camera.Size b) {  
  232. int aPixels = a.height * a.width;  
  233. int bPixels = b.height * b.width;  
  234. if (bPixels < aPixels) {  
  235. return -1;  
  236.                 }  
  237. if (bPixels > aPixels) {  
  238. return 1;  
  239.                 }  
  240. return 0;  
  241.             }  
  242.         });  
  243.   
  244. new StringBuilder();  
  245. for (Camera.Size supportedPreviewResolution : supportedPreviewResolutions) {  
  246. 'x').append(supportedPreviewResolution.height)  
  247. ' ');  
  248.         }  
  249.   
  250.   
  251. // 移除不符合条件的分辨率  
  252. double screenAspectRatio = (double) screenWidth  
  253.         / screenHeight;  
  254.         Iterator<Size> it = supportedPreviewResolutions.iterator();  
  255. while (it.hasNext()) {  
  256.             Camera.Size supportedPreviewResolution = it.next();  
  257. int width = supportedPreviewResolution.width;  
  258. int height = supportedPreviewResolution.height;  
  259.   
  260. // 移除低于下限的分辨率,尽可能取高分辨率  
  261. if (width * height < MIN_PREVIEW_PIXELS) {  
  262.                 it.remove();  
  263. continue;  
  264.             }  
  265.   
  266. // 在camera分辨率与屏幕分辨率宽高比不相等的情况下,找出差距最小的一组分辨率  
  267. // 由于camera的分辨率是width>height,我们设置的portrait模式中,width<height  
  268. // 因此这里要先交换然preview宽高比后在比较  
  269. boolean isCandidatePortrait = width > height;  
  270. int maybeFlippedWidth = isCandidatePortrait ? height : width;  
  271. int maybeFlippedHeight = isCandidatePortrait ? width : height;  
  272. double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight;  
  273. double distortion = Math.abs(aspectRatio - screenAspectRatio);  
  274. if (distortion > MAX_ASPECT_DISTORTION) {  
  275.                 it.remove();  
  276. continue;  
  277.             }  
  278.   
  279. // 找到与屏幕分辨率完全匹配的预览界面分辨率直接返回  
  280. if (maybeFlippedWidth == screenWidth  
  281.                     && maybeFlippedHeight == screenHeight) {  
  282. return supportedPreviewResolution;  
  283.             }  
  284.         }  
  285.   
  286.   
  287. // 如果没有找到合适的,并且还有候选的像素,则设置其中最大比例的,对于配置比较低的机器不太合适  
  288. if (!supportedPreviewResolutions.isEmpty()) {  
  289. 0);  
  290. return largestPreview;  
  291.         }  
  292.   
  293.   
  294. // 没有找到合适的,就返回默认的  
  295.   
  296. return defaultPreviewResolution;  
  297.     }  
  298.   
  299.   
  300. private Camera.Size findBestPictureResolution() {  
  301.         Camera.Parameters cameraParameters = mCamera.getParameters();  
  302. // 至少会返回一个值  
  303.   
  304. new StringBuilder();  
  305. for (Camera.Size supportedPicResolution : supportedPicResolutions) {  
  306. 'x')  
  307. " ");  
  308.         }  
  309.   
  310.         Camera.Size defaultPictureResolution = cameraParameters.getPictureSize();  
  311.   
  312. // 排序  
  313. new ArrayList<Camera.Size>(  
  314.                 supportedPicResolutions);  
  315. new Comparator<Camera.Size>() {  
  316. @Override  
  317. public int compare(Camera.Size a, Camera.Size b) {  
  318. int aPixels = a.height * a.width;  
  319. int bPixels = b.height * b.width;  
  320. if (bPixels < aPixels) {  
  321. return -1;  
  322.                 }  
  323. if (bPixels > aPixels) {  
  324. return 1;  
  325.                 }  
  326. return 0;  
  327.             }  
  328.         });  
  329.   
  330.   
  331. // 移除不符合条件的分辨率  
  332. double screenAspectRatio = screenWidth  
  333. double) screenHeight;  
  334.         Iterator<Camera.Size> it = sortedSupportedPicResolutions.iterator();  
  335. while (it.hasNext()) {  
  336.             Camera.Size supportedPreviewResolution = it.next();  
  337. int width = supportedPreviewResolution.width;  
  338. int height = supportedPreviewResolution.height;  
  339.   
  340. // 在camera分辨率与屏幕分辨率宽高比不相等的情况下,找出差距最小的一组分辨率  
  341. // 由于camera的分辨率是width>height,我们设置的portrait模式中,width<height  
  342. // 因此这里要先交换然后在比较宽高比  
  343. boolean isCandidatePortrait = width > height;  
  344. int maybeFlippedWidth = isCandidatePortrait ? height : width;  
  345. int maybeFlippedHeight = isCandidatePortrait ? width : height;  
  346. double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight;  
  347. double distortion = Math.abs(aspectRatio - screenAspectRatio);  
  348. if (distortion > MAX_ASPECT_DISTORTION) {  
  349.                 it.remove();  
  350. continue;  
  351.             }  
  352.         }  
  353.   
  354. // 如果没有找到合适的,并且还有候选的像素,对于照片,则取其中最大比例的,而不是选择与屏幕分辨率相同的  
  355. if (!sortedSupportedPicResolutions.isEmpty()) {  
  356. return sortedSupportedPicResolutions.get(0);  
  357.         }  
  358.   
  359. // 没有找到合适的,就返回默认的  
  360. return defaultPictureResolution;  
  361.     }  
  362.   
  363. private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {  
  364. final double ASPECT_TOLERANCE = 0.1;  
  365. double targetRatio = (double) w / h;  
  366. if (sizes == null)  
  367. return null;  
  368.   
  369. null;  
  370. double minDiff = Double.MAX_VALUE;  
  371.   
  372. int targetHeight = h;  
  373.   
  374. // Try to find an size match aspect ratio and size  
  375. for (Size size : sizes) {  
  376. double ratio = (double) size.width / size.height;  
  377. if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)  
  378. continue;  
  379. if (Math.abs(size.height - targetHeight) < minDiff) {  
  380.                 optimalSize = size;  
  381.                 minDiff = Math.abs(size.height - targetHeight);  
  382.             }  
  383.         }  
  384.   
  385. // Cannot find the one match the aspect ratio, ignore the requirement  
  386. if (optimalSize == null) {  
  387.             minDiff = Double.MAX_VALUE;  
  388. for (Size size : sizes) {  
  389. if (Math.abs(size.height - targetHeight) < minDiff) {  
  390.                     optimalSize = size;  
  391.                     minDiff = Math.abs(size.height - targetHeight);  
  392.                 }  
  393.             }  
  394.         }  
  395. return optimalSize;  
  396.     }  
  397.   
  398.   
  399. public void reAutoFocus() {  
  400. if (isSupportAutoFocus) {  
  401. new Camera.AutoFocusCallback() {  
  402. @Override  
  403. public void onAutoFocus(boolean success, Camera camera) {  
  404.                 }  
  405.             });  
  406.         }  
  407.     }  
  408.   
  409. public List<Size> getResolutionList() {  
  410. return mCamera.getParameters().getSupportedPreviewSizes();  
  411.     }  
  412.   
  413. public Camera.Size getResolution() {  
  414.         Camera.Parameters params = mCamera.getParameters();  
  415.         Camera.Size s = params.getPreviewSize();  
  416. return s;  
  417.     }  
  418.   
  419. /*public void setCurrentCameraId(int current) {
  420.         mCurrentCameraId = current;
  421.     }*/  
  422.   
  423. //定点对焦的代码  
  424. public void pointFocus(MotionEvent event) {  
  425.         mCamera.cancelAutoFocus();  
  426.         parameters = mCamera.getParameters();  
  427. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {  
  428. //showPoint(x, y);  
  429.             focusOnTouch(event);  
  430.         }  
  431.         mCamera.setParameters(parameters);  
  432.         autoFocus();  
  433.     }  
  434.   
  435. //实现自动对焦  
  436. public void autoFocus() {  
  437. new Thread() {  
  438. @Override  
  439. public void run() {  
  440. try {  
  441. 100);  
  442. catch (InterruptedException e) {  
  443.                     e.printStackTrace();  
  444.                 }  
  445. if (mCamera == null) {  
  446. return;  
  447.                 }  
  448. new Camera.AutoFocusCallback() {  
  449. @Override  
  450. public void onAutoFocus(boolean success, Camera camera) {  
  451. if (success) {  
  452. //实现相机的参数初始化  
  453.                         }  
  454.                     }  
  455.                 });  
  456.             }  
  457.         };  
  458.     }  
  459.   
  460. @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)  
  461. private void showPoint(int x, int y) {  
  462. if (parameters.getMaxNumMeteringAreas() > 0) {  
  463. new ArrayList<Camera.Area>();  
  464.             WindowManager wm = (WindowManager) getContext()  
  465.                     .getSystemService(Context.WINDOW_SERVICE);  
  466. //xy变换了  
  467. int rectY = -x * 2000 / wm.getDefaultDisplay().getWidth() + 1000;  
  468. int rectX = y * 2000 / wm.getDefaultDisplay().getHeight() - 1000;  
  469. int left = rectX < -900 ? -1000 : rectX - 100;  
  470. int top = rectY < -900 ? -1000 : rectY - 100;  
  471. int right = rectX > 900 ? 1000 : rectX + 100;  
  472. int bottom = rectY > 900 ? 1000 : rectY + 100;  
  473. new Rect(left, top, right, bottom);  
  474. new Camera.Area(area1, 800));  
  475.             parameters.setMeteringAreas(areas);  
  476.         }  
  477.   
  478.         parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);  
  479.     }  
  480.   
  481. @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)  
  482. public void focusOnTouch(MotionEvent event) {  
  483.         Rect focusRect = calculateTapArea(event.getRawX(), event.getRawY(), 1f);  
  484. 1.5f);  
  485.   
  486.         Camera.Parameters parameters = mCamera.getParameters();  
  487.         parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);  
  488.   
  489. if (parameters.getMaxNumFocusAreas() > 0) {  
  490. new ArrayList<Camera.Area>();  
  491. new Camera.Area(focusRect, 1000));  
  492.   
  493.             parameters.setFocusAreas(focusAreas);  
  494.         }  
  495.   
  496. if (parameters.getMaxNumMeteringAreas() > 0) {  
  497. new ArrayList<Camera.Area>();  
  498. new Camera.Area(meteringRect, 1000));  
  499.   
  500.             parameters.setMeteringAreas(meteringAreas);  
  501.         }  
  502.         mCamera.setParameters(parameters);  
  503. this);  
  504.     }  
  505.   
  506. /**
  507.      * Convert touch position x:y to {@link Camera.Area} position -1000:-1000 to 1000:1000.
  508.      */  
  509. private Rect calculateTapArea(float x, float y, float coefficient) {  
  510. float focusAreaSize = 300;  
  511. int areaSize = Float.valueOf(focusAreaSize * coefficient).intValue();  
  512.   
  513. int centerX = (int) (x / getResolution().width * 2000 - 1000);  
  514. int centerY = (int) (y / getResolution().height * 2000 - 1000);  
  515.   
  516. int left = clamp(centerX - areaSize / 2, -1000, 1000);  
  517. int right = clamp(left + areaSize, -1000, 1000);  
  518. int top = clamp(centerY - areaSize / 2, -1000, 1000);  
  519. int bottom = clamp(top + areaSize, -1000, 1000);  
  520.   
  521. return new Rect(left, top, right, bottom);  
  522.     }  
  523.   
  524. private int clamp(int x, int min, int max) {  
  525. if (x > max) {  
  526. return max;  
  527.         }  
  528. if (x < min) {  
  529. return min;  
  530.         }  
  531. return x;  
  532.     }  
  533.   
  534. @Override  
  535. public void onAutoFocus(boolean success, Camera camera) {  
  536.   
  537.     }  
  538.   
  539. public void setNull() {  
  540. null;  
  541. null;  
  542.     }  
  543.   
  544. }  


以下是CameraActivity类:


[java]  ​​view plain​​  ​​copy​​

 ​​print​​ ​​?​​

  1. public class CameraActivity extends Activity implements View.OnTouchListener,OnClickListener {  
  2.   
  3. public static final String CAMERA_PATH_VALUE1 = "PHOTO_PATH";  
  4. public static final String CAMERA_PATH_VALUE2 = "PATH";  
  5. public static final String CAMERA_TYPE = "CAMERA_TYPE";  
  6. public static final String CAMERA_RETURN_PATH = "return_path";  
  7.   
  8. private int PHOTO_SIZE_W = 2000;  
  9. private int PHOTO_SIZE_H = 2000;  
  10. public static final int CAMERA_TYPE_1 = 1;  
  11. public static final int CAMERA_TYPE_2 = 2;  
  12. private final int PROCESS = 1;  
  13. private CameraPreview preview;  
  14. private Camera camera;  
  15. private Context mContext;  
  16. private View focusIndex;  
  17. private ImageView flashBtn;  
  18. private int mCurrentCameraId = 0; // 1是前置 0是后置  
  19. private SurfaceView mSurfaceView;  
  20. private CameraGrid mCameraGrid;  
  21.   
  22. private int type = 1;   //引用的矩形框  
  23.   
  24. private Button mBtnSearch;  
  25. private Button mBtnTakePhoto;  
  26.   
  27. @Override  
  28. public void onCreate(Bundle savedInstanceState) {  
  29. super.onCreate(savedInstanceState);  
  30. this;  
  31.   
  32. //requestWindowFeature(Window.FEATURE_NO_TITLE);  
  33. //getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//全屏  
  34. //getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);//拍照过程屏幕一直处于高亮  
  35.         setContentView(R.layout.camera_home);  
  36.         type = getIntent().getIntExtra(CAMERA_TYPE, CAMERA_TYPE_2);  
  37.         initView();  
  38.         InitData();  
  39.   
  40.     }  
  41.   
  42. private void initView() {  
  43.         focusIndex = (View) findViewById(R.id.focus_index);  
  44.         flashBtn = (ImageView) findViewById(R.id.flash_view);  
  45.         mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);  
  46.         mCameraGrid = (CameraGrid) findViewById(R.id.camera_grid);  
  47.         mBtnSearch = (Button) findViewById(R.id.search);  
  48.         mBtnTakePhoto = (Button) findViewById(R.id.takephoto);  
  49.     }  
  50.   
  51.   
  52. private void InitData() {  
  53. new CameraPreview(this, mSurfaceView);  
  54. new LayoutParams(LayoutParams.MATCH_PARENT,  
  55.                 LayoutParams.MATCH_PARENT));  
  56.         ((FrameLayout) findViewById(R.id.layout)).addView(preview);  
  57. true);  
  58. this);  
  59.         mCameraGrid.setType(type);  
  60.     }  
  61.   
  62.   
  63.   
  64.   
  65. private Handler handler = new Handler();  
  66.   
  67. private void takePhoto() {  
  68. try {  
  69.   
  70.             camera.takePicture(shutterCallback, rawCallback, jpegCallback);  
  71.   
  72. catch (Throwable t) {  
  73.             t.printStackTrace();  
  74. "拍照失败,请重试!", Toast.LENGTH_LONG)  
  75.             .show();  
  76. try {  
  77.                 camera.startPreview();  
  78. catch (Throwable e) {  
  79.   
  80.             }  
  81.         }  
  82.     }  
  83.   
  84.   
  85.   
  86. @Override  
  87. protected void onResume() {  
  88. super.onResume();  
  89. int numCams = Camera.getNumberOfCameras();  
  90. if (numCams > 0) {  
  91. try {  
  92. 0;  
  93.                 camera = Camera.open(mCurrentCameraId);  
  94.                 camera.startPreview();  
  95.                 preview.setCamera(camera);  
  96.                 preview.reAutoFocus();  
  97. catch (RuntimeException ex) {  
  98. "未发现相机", Toast.LENGTH_LONG).show();  
  99.             }  
  100.         }  
  101.   
  102.     }  
  103.   
  104.   
  105.   
  106. @Override  
  107. protected void onPause() {  
  108. if (camera != null) {  
  109.             camera.stopPreview();  
  110. null);  
  111.             camera.release();  
  112. null;  
  113.             preview.setNull();  
  114.         }  
  115. super.onPause();  
  116.   
  117.     }  
  118.   
  119.   
  120. private void resetCam() {  
  121.         camera.startPreview();  
  122.         preview.setCamera(camera);  
  123.     }  
  124.   
  125.   
  126. new ShutterCallback() {  
  127. public void onShutter() {  
  128.         }  
  129.     };  
  130.   
  131.   
  132. new PictureCallback() {  
  133. public void onPictureTaken(byte[] data, Camera camera) {  
  134.         }  
  135.     };  
  136.   
  137.   
  138. new PictureCallback() {  
  139. public void onPictureTaken(byte[] data, Camera camera) {  
  140.   
  141. new SaveImageTask(data).execute();  
  142.             resetCam();  
  143.         }  
  144.     };  
  145.   
  146.   
  147. @Override  
  148. public boolean onTouch(View v, MotionEvent event) {  
  149. try {  
  150. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {  
  151.                 preview.pointFocus(event);  
  152.             }  
  153. catch (Exception e) {  
  154.             e.printStackTrace();  
  155.         }  
  156.   
  157. new RelativeLayout.LayoutParams(  
  158.                 focusIndex.getLayoutParams());  
  159. int) event.getX() - 60, (int) event.getY() - 60, 0,0);  
  160.   
  161.         focusIndex.setLayoutParams(layout);  
  162.         focusIndex.setVisibility(View.VISIBLE);  
  163.   
  164. new ScaleAnimation(3f, 1f, 3f, 1f,  
  165. 0.5f,  
  166. 0.5f);  
  167. 800);  
  168.         focusIndex.startAnimation(sa);  
  169. new Runnable() {  
  170. @Override  
  171. public void run() {  
  172.                 focusIndex.setVisibility(View.INVISIBLE);  
  173.             }  
  174. 800);  
  175. return false;  
  176.     }  
  177.   
  178.   
  179. @Override  
  180. public void onClick(View v) {  
  181. switch (v.getId()) {  
  182.   
  183. /*case R.id.camera_back:
  184.             setResult(0);
  185.             finish();
  186.             break;*/  
  187.   
  188. case R.id.camera_flip_view:  
  189.             switchCamera();  
  190. break;  
  191.   
  192. case R.id.flash_view:  
  193.             turnLight(camera);  
  194. break;  
  195.   
  196. case R.id.action_button:  
  197.             takePhoto();  
  198. break;  
  199.   
  200. case R.id.search:   //处理选中状态  
  201. true);  
  202. false);  
  203. break;  
  204.   
  205. case R.id.takephoto:    //处理选中状态  
  206. true);  
  207. false);  
  208. break;  
  209.         }  
  210.     }  
  211.   
  212. private static String getCameraPath() {  
  213.         Calendar calendar = Calendar.getInstance();  
  214. new StringBuilder();  
  215. "IMG");  
  216.         sb.append(calendar.get(Calendar.YEAR));  
  217. int month = calendar.get(Calendar.MONTH) + 1; // 0~11  
  218. 10 ? "0" + month : month);  
  219. int day = calendar.get(Calendar.DATE);  
  220. 10 ? "0" + day : day);  
  221. int hour = calendar.get(Calendar.HOUR_OF_DAY);  
  222. 10 ? "0" + hour : hour);  
  223. int minute = calendar.get(Calendar.MINUTE);  
  224. 10 ? "0" + minute : minute);  
  225. int second = calendar.get(Calendar.SECOND);  
  226. 10 ? "0" + second : second);  
  227. if (!new File(sb.toString() + ".jpg").exists()) {  
  228. return sb.toString() + ".jpg";  
  229.         }  
  230.   
  231. new StringBuilder(sb);  
  232. int indexStart = sb.length();  
  233. for (int i = 1; i < Integer.MAX_VALUE; i++) {  
  234. '(');  
  235.             tmpSb.append(i);  
  236. ')');  
  237. ".jpg");  
  238. if (!new File(tmpSb.toString()).exists()) {  
  239. break;  
  240.             }  
  241.   
  242.             tmpSb.delete(indexStart, tmpSb.length());  
  243.         }  
  244.   
  245. return tmpSb.toString();  
  246.     }  
  247.   
  248.   
  249.   
  250. //处理拍摄的照片  
  251. private class SaveImageTask extends AsyncTask<Void, Void, String> {  
  252. private byte[] data;  
  253.   
  254. byte[] data) {  
  255. this.data = data;  
  256.         }  
  257.   
  258. @Override  
  259. protected String doInBackground(Void... params) {  
  260. // Write to SD Card  
  261. "";  
  262. try {  
  263.   
  264. "处理中");  
  265.                 path = saveToSDCard(data);  
  266.   
  267. catch (FileNotFoundException e) {  
  268.                 e.printStackTrace();  
  269. catch (IOException e) {  
  270.                 e.printStackTrace();  
  271. finally {  
  272.             }  
  273. return path;  
  274.         }  
  275.   
  276.   
  277. @Override  
  278. protected void onPostExecute(String path) {  
  279. super.onPostExecute(path);  
  280.   
  281. if (!TextUtils.isEmpty(path)) {  
  282.   
  283. "DemoLog", "path=" + path);  
  284.   
  285.                 dismissProgressDialog();  
  286. new Intent();  
  287. this, PhotoProcessActivity.class);  
  288.                 intent.putExtra(CAMERA_PATH_VALUE1, path);  
  289.                 startActivityForResult(intent, PROCESS);  
  290. else {  
  291. "拍照失败,请稍后重试!",  
  292.                         Toast.LENGTH_LONG).show();  
  293.             }  
  294.         }  
  295.     }  
  296.   
  297. private AlertDialog mAlertDialog;  
  298.   
  299. private void dismissProgressDialog() {  
  300. this.runOnUiThread(new Runnable() {  
  301. @Override  
  302. public void run() {  
  303. if (mAlertDialog != null && mAlertDialog.isShowing()  
  304. this.isFinishing()) {  
  305.                     mAlertDialog.dismiss();  
  306. null;  
  307.                 }  
  308.             }  
  309.         });  
  310.     }  
  311.   
  312. private void showProgressDialog(final String msg) {  
  313. this.runOnUiThread(new Runnable() {  
  314. @Override  
  315. public void run() {  
  316. if (mAlertDialog == null) {  
  317. new GenericProgressDialog(  
  318. this);  
  319.                 }  
  320.                 mAlertDialog.setMessage(msg);  
  321.                 ((GenericProgressDialog) mAlertDialog)  
  322. true);  
  323. false);  
  324. null);  
  325.                 mAlertDialog.show();  
  326. false);  
  327.             }  
  328.         });  
  329.     }  
  330.   
  331.   
  332. /**
  333.      * 将拍下来的照片存放在SD卡中
  334.      */  
  335. public String saveToSDCard(byte[] data) throws IOException {  
  336.         Bitmap croppedImage;  
  337. // 获得图片大小  
  338. new BitmapFactory.Options();  
  339. true;  
  340. 0, data.length, options);  
  341. // PHOTO_SIZE = options.outHeight > options.outWidth ? options.outWidth  
  342. // : options.outHeight;  
  343.         PHOTO_SIZE_W = options.outWidth;  
  344.         PHOTO_SIZE_H = options.outHeight;  
  345. false;  
  346. new Rect(0, 0, PHOTO_SIZE_W, PHOTO_SIZE_H);  
  347. try {  
  348.             croppedImage = decodeRegionCrop(data, r);  
  349. catch (Exception e) {  
  350. return null;  
  351.         }  
  352. "";  
  353. try {  
  354.             imagePath = saveToFile(croppedImage);  
  355. catch (Exception e) {  
  356.   
  357.         }  
  358.         croppedImage.recycle();  
  359. return imagePath;  
  360.     }  
  361.   
  362.   
  363.   
  364. private Bitmap decodeRegionCrop(byte[] data, Rect rect) {  
  365. null;  
  366.         System.gc();  
  367. null;  
  368. try {  
  369. new ByteArrayInputStream(data);  
  370. false);  
  371. try {  
  372.                 croppedImage = decoder.decodeRegion(rect,  
  373. new BitmapFactory.Options());  
  374. catch (IllegalArgumentException e) {  
  375.             }  
  376. catch (Throwable e) {  
  377.             e.printStackTrace();  
  378. finally {  
  379.   
  380.         }  
  381. new Matrix();  
  382. 90, PHOTO_SIZE_W / 2, PHOTO_SIZE_H / 2);  
  383. if (mCurrentCameraId == 1) {  
  384. 1, -1);  
  385.         }  
  386. 0, 0,  
  387. true);  
  388. if (rotatedImage != croppedImage)  
  389.             croppedImage.recycle();  
  390. return rotatedImage;  
  391.     }  
  392.   
  393.   
  394.   
  395. // 保存图片文件  
  396. public static String saveToFile(Bitmap croppedImage)  
  397. throws FileNotFoundException, IOException {  
  398.         File sdCard = Environment.getExternalStorageDirectory();  
  399. new File(sdCard.getAbsolutePath() + "/DCIM/Camera/");  
  400. if (!dir.exists()) {  
  401.             dir.mkdirs();  
  402.         }  
  403.         String fileName = getCameraPath();  
  404. new File(dir, fileName);  
  405. new FileOutputStream(outFile); // 文件输出流  
  406. 70, outputStream);  
  407.         outputStream.flush();  
  408.         outputStream.close();  
  409. return outFile.getAbsolutePath();  
  410.     }  
  411.   
  412.   
  413. /**
  414.      * 闪光灯开关 开->关->自动
  415.      *
  416.      * @param mCamera
  417.      */  
  418. private void turnLight(Camera mCamera) {  
  419. if (mCamera == null || mCamera.getParameters() == null  
  420. null) {  
  421. return;  
  422.         }  
  423.         Camera.Parameters parameters = mCamera.getParameters();  
  424.         String flashMode = mCamera.getParameters().getFlashMode();  
  425.         List<String> supportedModes = mCamera.getParameters()  
  426.                 .getSupportedFlashModes();  
  427. if (Camera.Parameters.FLASH_MODE_OFF.equals(flashMode)  
  428. // 关闭状态  
  429.             parameters.setFlashMode(Camera.Parameters.FLASH_MODE_ON);  
  430.             mCamera.setParameters(parameters);  
  431.             flashBtn.setImageResource(R.drawable.camera_flash_on);  
  432. else if (Camera.Parameters.FLASH_MODE_ON.equals(flashMode)) {// 开启状态  
  433. if (supportedModes.contains(Camera.Parameters.FLASH_MODE_AUTO)) {  
  434.                 parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);  
  435.                 flashBtn.setImageResource(R.drawable.camera_flash_auto);  
  436.                 mCamera.setParameters(parameters);  
  437. else if (supportedModes  
  438.                     .contains(Camera.Parameters.FLASH_MODE_OFF)) {  
  439.                 parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);  
  440.                 flashBtn.setImageResource(R.drawable.camera_flash_off);  
  441.                 mCamera.setParameters(parameters);  
  442.             }  
  443. else if (Camera.Parameters.FLASH_MODE_AUTO.equals(flashMode)  
  444.                 && supportedModes.contains(Camera.Parameters.FLASH_MODE_OFF)) {  
  445.             parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);  
  446.             mCamera.setParameters(parameters);  
  447.             flashBtn.setImageResource(R.drawable.camera_flash_off);  
  448.         }  
  449.     }  
  450.   
  451.   
  452. // 切换前后置摄像头  
  453. private void switchCamera() {  
  454. 1) % Camera.getNumberOfCameras();  
  455. if (camera != null) {  
  456.             camera.stopPreview();  
  457. null);  
  458. null);  
  459.             camera.release();  
  460. null;  
  461.         }  
  462. try {  
  463.             camera = Camera.open(mCurrentCameraId);  
  464.             camera.setPreviewDisplay(mSurfaceView.getHolder());  
  465.             preview.setCamera(camera);  
  466.             camera.startPreview();  
  467. catch (Exception e) {  
  468. "未发现相机", Toast.LENGTH_LONG).show();  
  469.         }  
  470.   
  471.     }  
  472.   
  473. @Override  
  474. public boolean onKeyDown(int keyCode, KeyEvent event) {  
  475. if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {  
  476. 0);  
  477.             finish();  
  478. return true;  
  479.         }  
  480. return super.onKeyDown(keyCode, event);  
  481.     }  
  482.   
  483.   
  484. @Override  
  485. public void onActivityResult(int requestCode, int resultCode, Intent data) {  
  486. if (requestCode == PROCESS) {  
  487. if (resultCode == RESULT_OK) {  
  488. new Intent();  
  489. if (data != null) {  
  490.                     intent.putExtra(CAMERA_RETURN_PATH,  
  491.                             data.getStringExtra(CAMERA_PATH_VALUE2));  
  492.                 }  
  493.                 setResult(RESULT_OK, intent);  
  494.                 finish();  
  495. else {  
  496. if (data != null) {  
  497. new File(data.getStringExtra(CAMERA_PATH_VALUE2));  
  498. if (dir != null) {  
  499.                         dir.delete();  
  500.                     }  
  501.                 }  
  502.             }  
  503.         }  
  504.     }  
  505. }  




总结

1、网上有些示例代码,担心相机初始化及开启时间较长,将初始化及启动工作单独放在子线程中,偶尔出现黑屏的情况,但也不是经常出现。

导致原因:由于单独开辟了线程去初始化启动相机,导致相机的初始化和开启工作已完成,而找不到画布控件。若出现此情况,可调试或者将线程睡眠500毫秒。


2、按下home键后,再次进入时,为毛黑屏了,如何破?

导致原因:在onCreate中find了SurfaceView,按下Home后程序再次进入时,找不到预览的画布了,可将find的工作放入onResume中,再就是别忘了在onPause中做如下操作:


[java]  ​​view plain​​  ​​copy​​

 ​​print​​ ​​?​​

  1. @Override  
  2. protected void onPause() {  
  3. if (camera != null) {  
  4.             camera.stopPreview();  
  5. null);  
  6.             camera.release();  
  7. null;  
  8.             preview.setNull();  
  9.         }  
  10. super.onPause();  
  11.   
  12.     }