杂家前文是在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. 基于TcpListener的web服务器

    写在前面 上篇文章根据<asp.net 本质论>书上提供的例子,实现了一个简单的web服务器,本篇文章将介绍另一种实现方式——基于TcpListener的web服务器. TcpListen ...

  2. GCC 编译详解

    GNU CC(简称为Gcc)是GNU项目中符合ANSI C标准的编译系统,能够编译用C.C++和Object C等语言编写的程序.Gcc不仅功能强大,而且可以编译如C.C++.Object C.Jav ...

  3. Entity Framework 系统约定配置

    前言 Code First之所以能够让开发人员以一种更加高效.灵活的方式进行数据操作有一个重要的原因在于它的约定配置.现在软件开发越来越复杂,大家都试图将软件设计的越来越灵活,很多内容我们都希望是可配 ...

  4. Procrustes Analysis普氏分析法

    选取N幅同类目标物体的二维图像,并用上一篇博文的方法标注轮廓点,这样就得到训练样本集: 由于图像中目标物体的形状和位置存在较大偏差,因此所得到的数据并不具有仿射不变性,需要对其进行归一化处理.这里采用 ...

  5. zoj3745 Salary Increasing

    OJ Problem Set - 3745 Salary Increasing Time Limit: 2 Seconds      Memory Limit: 65536 KB Edward has ...

  6. MySQL数据库索引的4大类型以及相关的索引创建

    以下的文章主要介绍的是MySQL数据库索引类型,其中包括普通索引,唯一索引,主键索引与主键索引,以及对这些索引的实际应用或是创建有一个详细介绍,以下就是文章的主要内容描述. (1)普通索引 这是最基本 ...

  7. sass的视频教程

    http://www.w3ci.com/video/715.html http://koala-app.com/index-zh.html /***************三角形的应用******** ...

  8. operator new3种情况详解

    [本文链接] http://www.cnblogs.com/hellogiser/p/operator-new.html [代码]  C++ Code  12345678910111213141516 ...

  9. redis 初探

    2014年6月24日 17:50:57 解压redis后进入源码目录,只用执行make命令就可以完成安装了 安装完成后到src目录里,将 redis-server redis-cli redis.co ...

  10. jQuery ajax跨域请求的解决方法

    在Ajax应用中,jQuery的Ajax请求是非常容易而且方便的,但是初学者经常会犯一个错误,那就是Ajax请求的url不是本地或者同一个服务器下面的URI,最后导致虽然请求200,但是不会返回任何数 ...