当前位置:   article > 正文

Android相机开发实战_msupportedresolutions

msupportedresolutions

开源分享二(Android相机开发实战)



开源分享 一(StickerCamera + 仿微信多图选择)

开源分享三(炫酷的Android Loading动画)


前言


上篇博文给大家分享了两个非常实用的项目功能模块,不知道大伙感觉如何?有木有一种臭袜子味扑鼻,酸爽的赶脚!!!贱笑贱笑了~ ~

OK!不扯淡了,言归正传。本文将主要为大家介绍Android中自定义相机的开发,做Android应用的童鞋应该都知道,在应用中使用相机功能有两种方式:

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

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

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

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


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




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


GitHub:https://github.com/xplodwild/android_packages_apps_Focal



相机开发简介

下面说说在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权限,例如:

  1. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
  2. <uses-permission android:name="android.permission.CAMERA"/>
  3. <uses-feature android:name="android.hardware.camera" />
  4. <uses-permission android:name="android.hardware.camera.autofocus" />
  5. <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的示例相机模块,此功能模块并非上面开源项目中的剥离出来的,看下效果图咯:

         


         



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

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


下面是核心模块 CameraPreview 类:

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


以下是CameraActivity类:

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


总结

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

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


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

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

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

本项目源码(Eclipse版):http://download.csdn.net/download/gao_chun/9084853

注:测试机-------> 小米2A、红米、华为P8、华为荣耀3C,魅蓝note2


附:有些小伙伴经常问手机Gif动画如何制作的,在此也分享下:

动画制作小软件GifMaker:http://download.csdn.net/detail/gao_chun/9077023



【转载注明gao_chun的Blog:http://blog.csdn.net/gao_chun/article/details/48246871】



声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/102788
推荐阅读
相关标签
  

闽ICP备14008679号