本讲内容:Android手机摄像头编程入门
智能手机中的摄像头和普通手机中的摄像头最大的区别在于,智能机上的摄像头可以由程序员写程序控制,做一些有趣的应用譬如,画中画,做一些有用的应用譬如二维码识别,等等。本讲打算通过一个实例,来介绍一下摄像头编程,相关解释都写在代码中了,请注意看代码注释。
实例:窈窈照相机,功能很简单,就是点击程序弹出照相预览界面,点击相机按钮完成照相功能,所照相片会存储在手机存储卡根目录。
1、创建一个项目 Lesson36_Camera ,主程序文件为 MainActivity.java
2、AndroidManifest.xml 中设置屏幕为横屏,并且声明摄像头和存储卡的使用权限,具体代码如下:
01 | <?xml version= "1.0" encoding= "utf-8" ?> |
03 | <application android:label= "@string/app_name" android:icon= "@drawable/icon" > |
04 | <activity android:label= "@string/app_name" android:name= ".MainActivity" android:screenorientation= "landscape" android:configchanges= "orientation|keyboardHidden|keyboard" > |
06 | <action android:name= "android.intent.action.MAIN" > |
07 | <category android:name= "android.intent.category.LAUNCHER" > |
08 | </category></action></intent> |
12 | <uses -sdk= "" android:minsdkversion= "8" > |
13 | <uses -permission= "" android:name= "android.permission.CAMERA" ></uses> |
14 | <uses -permission= "" android:name= "android.permission.WRITE_EXTERNAL_STORAGE" ></uses> |
15 | <uses -feature= "" android:name= "android.hardware.camera" > |
16 | <uses -feature= "" android:name= "android.hardware.camera.autofocus" > |
17 | </uses></uses></uses></manifest> |
3、本例中不需要布局文件main.xml,因为本例中的UI组建都是动态添加上去的。
4、最后MainActivity.java的代码如下:
001 | package basic.android.lesson36; |
003 | import java.io.BufferedOutputStream; |
005 | import java.io.FileOutputStream; |
006 | import java.io.IOException; |
007 | import java.util.Calendar; |
008 | import java.util.Locale; |
010 | import android.app.Activity; |
011 | import android.content.Context; |
012 | import android.graphics.Bitmap; |
013 | import android.graphics.BitmapFactory; |
014 | import android.graphics.PixelFormat; |
015 | import android.hardware.Camera; |
016 | import android.os.Bundle; |
017 | import android.text.format.DateFormat; |
018 | import android.util.Log; |
019 | import android.view.KeyEvent; |
020 | import android.view.SurfaceHolder; |
021 | import android.view.SurfaceView; |
022 | import android.view.Window; |
023 | import android.view.WindowManager; |
024 | import android.widget.FrameLayout; |
025 | import android.widget.TextView; |
026 | import android.widget.Toast; |
028 | public class MainActivity extends Activity { |
030 | private CameraView cv; |
032 | private Camera mCamera = null ; |
034 | private Bitmap mBitmap = null ; |
037 | public Camera.PictureCallback pictureCallback = new Camera.PictureCallback() { |
039 | public void onPictureTaken( byte [] data, Camera camera) { |
040 | Log.i( "yao" , "onPictureTaken" ); |
041 | Toast.makeText(getApplicationContext(), "正在保存……" , Toast.LENGTH_LONG).show(); |
043 | mBitmap = BitmapFactory.decodeByteArray(data, 0 , data.length); |
045 | File file = new File( "/sdcard/YY" + new DateFormat().format( "yyyyMMdd_hhmmss" , Calendar.getInstance(Locale.CHINA)) + ".jpg" ); |
047 | file.createNewFile(); |
048 | BufferedOutputStream os = new BufferedOutputStream( new FileOutputStream(file)); |
049 | mBitmap.compress(Bitmap.CompressFormat.PNG, 100 , os); |
052 | Toast.makeText(getApplicationContext(), "图片保存完毕,在存储卡的根目录" , Toast.LENGTH_LONG).show(); |
053 | } catch (IOException e) { |
062 | public void onCreate(Bundle savedInstanceState) { |
063 | super .onCreate(savedInstanceState); |
066 | requestWindowFeature(Window.FEATURE_NO_TITLE); |
068 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN); |
070 | getWindow().setFormat(PixelFormat.TRANSLUCENT); |
073 | FrameLayout fl = new FrameLayout( this ); |
076 | cv = new CameraView( this ); |
080 | TextView tv = new TextView( this ); |
081 | tv.setText( "请按\"相机\"按钮拍摄" ); |
090 | public boolean onKeyDown( int keyCode, KeyEvent event) { |
091 | Log.i( "yao" , "MainActivity.onKeyDown" ); |
092 | if (keyCode == KeyEvent.KEYCODE_CAMERA) { |
093 | if (mCamera != null ) { |
094 | Log.i( "yao" , "mCamera.takePicture" ); |
096 | mCamera.takePicture( null , null , pictureCallback); |
099 | return cv.onKeyDown(keyCode, event); |
103 | class CameraView extends SurfaceView { |
105 | private SurfaceHolder holder = null ; |
108 | public CameraView(Context context) { |
110 | Log.i( "yao" , "CameraView" ); |
113 | holder = this .getHolder(); |
115 | holder.addCallback( new SurfaceHolder.Callback() { |
118 | public void surfaceDestroyed(SurfaceHolder holder) { |
120 | mCamera.stopPreview(); |
127 | public void surfaceCreated(SurfaceHolder holder) { |
129 | mCamera = Camera.open(); |
132 | mCamera.setPreviewDisplay(holder); |
133 | } catch (IOException e) { |
143 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { |
146 | Camera.Parameters parameters = mCamera.getParameters(); |
148 | parameters.setPictureFormat(PixelFormat.JPEG); |
150 | parameters.setPreviewSize( 854 , 480 ); |
152 | parameters.setFocusMode( "auto" ); |
154 | parameters.setPictureSize( 2592 , 1456 ); |
156 | mCamera.setParameters(parameters); |
158 | mCamera.startPreview(); |
162 | holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); |
5、连接Milestone,编译并运行程序:悲剧的是,截图只能看到黑黑的一片,无法截取到摄像头传输过来SurfaceView信息,而在真机中是能看到预览效果的。
还是上一张照好的图片给大家吧,(用了好多年的小黑……)
好了,本讲就到这里,谢谢大家的支持和鼓励,下次再见。