杂家前文是在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

  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. <org.yanzi.camera.preview.CameraSurfaceView
  10. android:id="@+id/camera_surfaceview"
  11. android:layout_width="0dip"
  12. android:layout_height="0dip" />
  13. </FrameLayout>
  14. <ImageButton
  15. android:id="@+id/btn_shutter"
  16. android:layout_width="wrap_content"
  17. android:layout_height="wrap_content"
  18. android:background="@drawable/btn_shutter_background"
  19. android:layout_alignParentBottom="true"
  20. android:layout_centerHorizontal="true"
  21. android:layout_marginBottom="10dip"/>
  22. </RelativeLayout>
  23. </span>

二、AndroidManifest.xml

  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. <uses-sdk
  7. android:minSdkVersion="9"
  8. android:targetSdkVersion="17" />
  9. <!-- 增加文件存储和访问摄像头的权限 -->
  10. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
  11. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  12. <uses-permission android:name="android.permission.CAMERA" />
  13. <uses-feature android:name="android.hardware.camera" />
  14. <application
  15. android:allowBackup="true"
  16. android:icon="@drawable/ic_launcher_icon"
  17. android:label="@string/app_name"
  18. android:theme="@style/AppTheme" >
  19. <activity
  20. android:name="org.yanzi.activity.CameraActivity"
  21. android:label="@string/app_name"
  22. android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
  23. android:screenOrientation="portrait">
  24. <intent-filter>
  25. <action android:name="android.intent.action.MAIN" />
  26. <category android:name="android.intent.category.LAUNCHER" />
  27. </intent-filter>
  28. </activity>
  29. </application>
  30. </manifest>
  31. </span>

三、下面是java代码

1、CameraActivity.Java

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

2、CameraInterface.java

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

3、CameraSurfaceView.java

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

4、CamParaUtil.java

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

5、DisplayUtil.java

  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.util;
  2. import android.content.Context;
  3. import android.graphics.Point;
  4. import android.util.DisplayMetrics;
  5. import android.util.Log;
  6. public class DisplayUtil {
  7. private static final String TAG = "DisplayUtil";
  8. /**
  9. * dip转px
  10. * @param context
  11. * @param dipValue
  12. * @return
  13. */
  14. public static int dip2px(Context context, float dipValue){
  15. final float scale = context.getResources().getDisplayMetrics().density;
  16. return (int)(dipValue * scale + 0.5f);
  17. }
  18. /**
  19. * px转dip
  20. * @param context
  21. * @param pxValue
  22. * @return
  23. */
  24. public static int px2dip(Context context, float pxValue){
  25. final float scale = context.getResources().getDisplayMetrics().density;
  26. return (int)(pxValue / scale + 0.5f);
  27. }
  28. /**
  29. * 获取屏幕宽度和高度,单位为px
  30. * @param context
  31. * @return
  32. */
  33. public static Point getScreenMetrics(Context context){
  34. DisplayMetrics dm =context.getResources().getDisplayMetrics();
  35. int w_screen = dm.widthPixels;
  36. int h_screen = dm.heightPixels;
  37. Log.i(TAG, "Screen---Width = " + w_screen + " Height = " + h_screen + " densityDpi = " + dm.densityDpi);
  38. return new Point(w_screen, h_screen);
  39. }
  40. /**
  41. * 获取屏幕长宽比
  42. * @param context
  43. * @return
  44. */
  45. public static float getScreenRate(Context context){
  46. Point P = getScreenMetrics(context);
  47. float H = P.y;
  48. float W = P.x;
  49. return (H/W);
  50. }
  51. }
  52. </span>

6、FileUtil.java

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

7、ImageUtil.java

  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.util;
  2. import android.graphics.Bitmap;
  3. import android.graphics.Matrix;
  4. public class ImageUtil {
  5. /**
  6. * 旋转Bitmap
  7. * @param b
  8. * @param rotateDegree
  9. * @return
  10. */
  11. public static Bitmap getRotateBitmap(Bitmap b, float rotateDegree){
  12. Matrix matrix = new Matrix();
  13. matrix.postRotate((float)rotateDegree);
  14. Bitmap rotaBitmap = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), matrix, false);
  15. return rotaBitmap;
  16. }
  17. }
  18. </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

百度云盘:

玩转Android Camera开发(一):Surfaceview预览Camera,基础拍照功能完整demo的更多相关文章

  1. Android Camera开发:使用GLSurfaceView预览Camera 基础拍照

    GLSurfaceView是OpenGL中的一个类,也是可以预览Camera的,而且在预览Camera上有其独到之处.独到之处在哪?当使用Surfaceview无能为力.痛不欲生时就只有使用GLSur ...

  2. 玩转Android Camera开发(二):使用TextureView和SurfaceTexture预览Camera 基础拍照demo

    Google自Android4.0出了TextureView,为什么推出呢?就是为了弥补Surfaceview的不足,另外一方面也是为了平衡GlSurfaceView,当然这是本人揣度的.关于Text ...

  3. Android Camera开发:使用TextureView和SurfaceTexture预览Camera 基础拍照demo

    Google自Android4.0出了TextureView,为什么推出呢?就是为了弥补Surfaceview的不足,另外一方面也是为了平衡GlSurfaceView,当然这是本人揣度的.关于Text ...

  4. Android摄像头:只拍摄SurfaceView预览界面特定区域内容(矩形框)---完整(原理:底层SurfaceView+上层绘制ImageView)

    Android摄像头:只拍摄SurfaceView预览界面特定区域内容(矩形框)---完整实现(原理:底层SurfaceView+上层绘制ImageView) 分类: Android开发 Androi ...

  5. 【转】玩转Android Camera开发(三):国内首发---使用GLSurfaceView预览Camera 基础拍照demo

    http://blog.csdn.net/yanzi1225627/article/details/33339965 GLSurfaceView是OpenGL中的一个类,也是可以预览Camera的,而 ...

  6. 玩转Android Camera开发(三):国内首发---使用GLSurfaceView预览Camera 基础拍照demo

    GLSurfaceView是OpenGL中的一个类,也是能够预览Camera的,并且在预览Camera上有其独到之处. 独到之处在哪?当使用Surfaceview无能为力.痛不欲生时就仅仅有使用GLS ...

  7. Android开发实践:掌握Camera的预览方向和拍照方向

    http://ticktick.blog.51cto.com/823160/1592267?utm_source=tuicool&utm_medium=referral Android的Cam ...

  8. Android Camera开发系列(上)——Camera的基本调用与实现拍照功能以及获取拍照图片加载大图片

    Android Camera开发系列(上)--Camera的基本调用与实现拍照功能以及获取拍照图片加载大图片 最近也是在搞个破相机,兼容性那叫一个不忍直视啊,于是自己翻阅了一些基本的资料,自己实现了一 ...

  9. Android开发 Camera2开发_2_预览分辨率或拍照分辨率的计算

    前言 不管在Camera1或者Camera2在适配不同手机/不同使用场景的情况下都需要计算摄像头里提供的分辨率列表中最合适的那一个分辨率.所以在需要大量机型适配的app,是不建议不经过计算直接自定义分 ...

随机推荐

  1. whereis命令

    whereis命令只能用于程序名的搜索,而且只搜索二进制文件(参数-b).man说明文件(参数-m)和源代码文件(参数-s).如果省略参数,则返回所有信息. 和find相比,whereis查找的速度非 ...

  2. 每日一练(写不出心得体会了!毕竟哪有那么多心得好写。然后看github上有很多不错的题目。分享一下!)

    第一题: 问题描述:写一个reverseWords函数 调用方式:console.log(reverseWords('Hello World')); 期望输出:World Hello 第二题: 问题描 ...

  3. PHP访问,增删改查,小结

    PHP访问数据,增,删,改,查 增: 1,add.php 显示页面,利用 <form> 表单添加数据,数据添加到 name 中. 2,addchuli.php 处理页面,定义变量接受 $_ ...

  4. MSSQL复习

    1.用户角色: 登录名就相当于一个用户 角色相当于把你的操作权限分组了 2.数据系统结构(略) 网络连接接口 关系引擎 存储引擎 内存 3.数据库的结构 数据库 架构 对象(在Sql server中将 ...

  5. 关于windows程序的学习及思考系列之一

    1.窗口类的注册 a.windows程序中最简单的就是创建一个简单的窗口,而窗口程序的创建是基于窗口类的,窗口类决定了处理窗口消息的过程函数. b.一个窗口类可以用于创建多个窗口,也就是说窗口是窗口类 ...

  6. 在VMware的虚拟机平台上如何进行网络设置

    1.本文构建的是这样一个网络,有两台winXP系统的PC,处于同一局域网内,PC里 都装有VMware虚拟机,虚拟机上跑的是Redhat Linux 9,我们想要在winXP系统下访问本机的虚拟机li ...

  7. 全面解释StringBuilder、StringBuffer和String的关系

    1. String 类    String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且大量浪费有限的内存空间.   String a = " ...

  8. jquery check box

    if ($("#eulaLine").is(':checked')) { var mobile = $("#mobile").val(); if (mobile ...

  9. object-c 系列教程

    1.object-c 基本数据类型 2.object-c 控制语句 3.object-c面向对象1 4.object-c面向对象2 5.object-c 继承多态 动态数据类型

  10. 如何在Ubuntu下安装”.deb“、”.bin“、”.tar.gz“、”.tar.bz2“格式的软件包!

    今天在Ubuntu11.10中安装Google chrome浏览器是遇到了问题,下载好的“.deb”格式的安装文件google-chrome-stable.deb双击后或者右键快捷菜单选择 Synap ...