本讲内容: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信息,而在真机中是能看到预览效果的。
还是上一张照好的图片给大家吧,(用了好多年的小黑……)
好了,本讲就到这里,谢谢大家的支持和鼓励,下次再见。