智能手机中的摄像头和普通手机中的摄像头最大的区别在于,智能机上的摄像头可以由程序员写程序控制,做一些有趣的应用譬如,画中画,做一些有用的应用譬如二维码识别,等等。本讲打算通过一个实例,来介绍一下摄像头编程,相关解释都写在代码中了,请注意看代码注释。

       实例:窈窈照相机,功能很简单,就是点击程序弹出照相预览界面,点击相机按钮完成照相功能,所照相片会存储在手机存储卡根目录。

       1、创建一个项目 Lesson36_Camera ,主程序文件为 MainActivity.java。

       2、AndroidManifest.xml 中设置屏幕为横屏,并且声明摄像头和存储卡的使用权限,具体代码如下:

XML/HTML代码
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <MANIFEST android:versionname="1.0" android:versioncode="1" xmlns:android="http://schemas.android.com/apk/res/android" package="basic.android.lesson36">  
  3.     <APPLICATION android:icon="@drawable/icon" android:label="@string/app_name">  
  4.         <ACTIVITY android:name=".MainActivity" android:label="@string/app_name" android:configchanges="orientation|keyboardHidden|keyboard" android:screenorientation="landscape">  
  5.             <INTENT -filter>  
  6.                 <ACTION android:name="android.intent.action.MAIN" />  
  7.                 <CATEGORY android:name="android.intent.category.LAUNCHER" />  
  8.             </INTENT>  
  9.         </ACTIVITY>  
  10.   
  11.     </APPLICATION>  
  12.     <USES android:minsdkversion="8" -sdk />  
  13.     <USES android:name="android.permission.CAMERA" -permission></USES>  
  14.     <USES android:name="android.permission.WRITE_EXTERNAL_STORAGE" -permission></USES>  
  15.     <USES android:name="android.hardware.camera" -feature />  
  16.     <USES android:name="android.hardware.camera.autofocus" -feature />  
  17. </MANIFEST>    

       3、本例中不需要布局文件main.xml,因为本例中的UI组建都是动态添加上去的。

       4、最后MainActivity.java的代码如下:

Java代码
  1. package basic.android.lesson36;   
  2.   
  3. import java.io.BufferedOutputStream;   
  4. import java.io.File;   
  5. import java.io.FileOutputStream;   
  6. import java.io.IOException;   
  7. import java.util.Calendar;   
  8. import java.util.Locale;   
  9.   
  10. import android.app.Activity;   
  11. import android.content.Context;   
  12. import android.graphics.Bitmap;   
  13. import android.graphics.BitmapFactory;   
  14. import android.graphics.PixelFormat;   
  15. import android.hardware.Camera;   
  16. import android.os.Bundle;   
  17. import android.text.format.DateFormat;   
  18. import android.util.Log;   
  19. import android.view.KeyEvent;   
  20. import android.view.SurfaceHolder;   
  21. import android.view.SurfaceView;   
  22. import android.view.Window;   
  23. import android.view.WindowManager;   
  24. import android.widget.FrameLayout;   
  25. import android.widget.TextView;   
  26. import android.widget.Toast;   
  27.   
  28. public class MainActivity extends Activity {   
  29.   
  30.     private CameraView cv;   
  31.     //准备一个相机对象   
  32.     private Camera mCamera = null;   
  33.     //准备一个Bitmap对象   
  34.     private Bitmap mBitmap = null;     
  35.   
  36.     //准备一个保存图片的PictureCallback对象   
  37.     public Camera.PictureCallback pictureCallback = new Camera.PictureCallback() {   
  38.   
  39.         public void onPictureTaken(byte[] data, Camera camera) {   
  40.             Log.i("yao","onPictureTaken");   
  41.             Toast.makeText(getApplicationContext(), "正在保存……", Toast.LENGTH_LONG).show();   
  42.             //用BitmapFactory.decodeByteArray()方法可以把相机传回的裸数据转换成Bitmap对象   
  43.             mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);   
  44.             //接下来的工作就是把Bitmap保存成一个存储卡中的文件   
  45.             File file = new File("/sdcard/YY"new DateFormat().format("yyyyMMdd_hhmmss", Calendar.getInstance(Locale.CHINA)) + ".jpg");   
  46.             try {   
  47.                 file.createNewFile();   
  48.                 BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(file));   
  49.                 mBitmap.compress(Bitmap.CompressFormat.PNG, 100, os);   
  50.                 os.flush();   
  51.                 os.close();   
  52.                 Toast.makeText(getApplicationContext(), "图片保存完毕,在存储卡的根目录", Toast.LENGTH_LONG).show();   
  53.             } catch (IOException e) {   
  54.                 e.printStackTrace();   
  55.             }   
  56.         }   
  57.   
  58.     };   
  59.   
  60.     //Activity的创建方法   
  61.     @Override  
  62.     public void onCreate(Bundle savedInstanceState) {   
  63.         super.onCreate(savedInstanceState);   
  64.   
  65.         //窗口去掉标题   
  66.         requestWindowFeature(Window.FEATURE_NO_TITLE);   
  67.         //窗口设置为全屏   
  68.         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);   
  69.         //设置窗口为半透明   
  70.         getWindow().setFormat(PixelFormat.TRANSLUCENT);   
  71.   
  72.         //提供一个帧布局   
  73.         FrameLayout  fl = new FrameLayout(this);         
  74.   
  75.         //创建一个照相预览用的SurfaceView子类,并放在帧布局的底层   
  76.         cv = new CameraView(this);   
  77.         fl.addView(cv);   
  78.   
  79.         //创建一个文本框添加在帧布局中,我们可以看到,文字自动出现在了SurfaceView的前面,由此你可以在预览窗口做出各种特殊效果   
  80.         TextView tv = new TextView(this);   
  81.         tv.setText("请按\"相机\"按钮拍摄");   
  82.         fl.addView(tv);   
  83.   
  84.         //设置Activity的根内容视图   
  85.         setContentView(fl);   
  86.   
  87.     }   
  88.   
  89.     //相机按键按下的事件处理方法   
  90.     public boolean onKeyDown(int keyCode, KeyEvent event) {   
  91.         Log.i("yao","MainActivity.onKeyDown");   
  92.         if (keyCode == KeyEvent.KEYCODE_CAMERA) {   
  93.             if (mCamera != null) {   
  94.                 Log.i("yao","mCamera.takePicture");   
  95.                 //当按下相机按钮时,执行相机对象的takePicture()方法,该方法有三个回调对象做入参,不需要的时候可以设null   
  96.                 mCamera.takePicture(nullnull, pictureCallback);   
  97.             }   
  98.         }   
  99.         return cv.onKeyDown(keyCode, event);   
  100.     }   
  101.   
  102.     // 照相视图   
  103.     class CameraView extends SurfaceView {   
  104.   
  105.         private SurfaceHolder holder = null;   
  106.   
  107.         //构造函数   
  108.         public CameraView(Context context) {   
  109.             super(context);   
  110.             Log.i("yao","CameraView");   
  111.   
  112.             // 操作surface的holder   
  113.             holder = this.getHolder();   
  114.             // 创建SurfaceHolder.Callback对象   
  115.             holder.addCallback(new SurfaceHolder.Callback() {   
  116.   
  117.                 @Override  
  118.                 public void surfaceDestroyed(SurfaceHolder holder) {   
  119.                     // 停止预览   
  120.                     mCamera.stopPreview();   
  121.                     // 释放相机资源并置空   
  122.                     mCamera.release();   
  123.                     mCamera = null;   
  124.                 }   
  125.   
  126.                 @Override  
  127.                 public void surfaceCreated(SurfaceHolder holder) {   
  128.                     //当预览视图创建的时候开启相机   
  129.                     mCamera = Camera.open();   
  130.                     try {   
  131.                         //设置预览   
  132.                         mCamera.setPreviewDisplay(holder);   
  133.                     } catch (IOException e) {   
  134.                         // 释放相机资源并置空   
  135.                         mCamera.release();   
  136.                         mCamera = null;   
  137.                     }   
  138.   
  139.                 }   
  140.   
  141.                 //当surface视图数据发生变化时,处理预览信息   
  142.                 @Override  
  143.                 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {   
  144.   
  145.                     //获得相机参数对象   
  146.                     Camera.Parameters parameters = mCamera.getParameters();   
  147.                     //设置格式   
  148.                     parameters.setPictureFormat(PixelFormat.JPEG);   
  149.                     //设置预览大小,这里我的测试机是Milsstone所以设置的是854x480   
  150.                     parameters.setPreviewSize(854480);   
  151.                     //设置自动对焦   
  152.                     parameters.setFocusMode("auto");   
  153.                     //设置图片保存时的分辨率大小   
  154.                     parameters.setPictureSize(25921456);   
  155.                     //给相机对象设置刚才设定的参数   
  156.                     mCamera.setParameters(parameters);   
  157.                     //开始预览   
  158.                     mCamera.startPreview();   
  159.                 }   
  160.             });   
  161.             // 设置Push缓冲类型,说明surface数据由其他来源提供,而不是用自己的Canvas来绘图,在这里是由摄像头来提供数据   
  162.             holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);   
  163.         }   
  164.   
  165.     }   
  166.   
  167. }  

       5、连接Milestone,编译并运行程序:悲剧的是,截图只能看到黑黑的一片,无法截取到摄像头传输过来SurfaceView信息,而在真机中是能看到预览效果的。

Android学习指南之三十六:Android手机摄像头开发初步

       还是上一张照好的图片给大家吧,(用了好多年的小黑……)

Android学习指南之三十六:Android手机摄像头开发初步

       好了,本讲就到这里,谢谢大家的支持和鼓励,下次再见。

本文发布:Android开发网
本文地址:http://www.jizhuomi.com/android/course/252.html
2012年10月28日
发布:鸡啄米 分类:Android开发教程 浏览: 评论:2