xdwangiflytek 发表于 2013-1-30 04:02:57

Android学习11-----多媒体技术(4) 使用摄像头拍照,多点触控

一、摄像头拍照
前面说媒体播放时了解了SurfaceView最大的特点就是提供了一个高速的更新空间,那么如果说现在要进行图像的捕获,那么肯定要跟随摄像头一起变化,那么这块空间很明显必须使用高速的刷新频率。
         使用SurfaceView组件可以进行视频文件的播放,而同样可以继续利用SurfaceView实现拍照的浏览功能,在支持拍照的手机上,都会为用户提供一个预览的屏幕显示当前摄像头所采集到的图片,而这种功能可以利用SurfaceView实现,SurfaceView之中的操作核心就是在于android.view. SurfaceHolder对象的操作,前面说了可以通过SurfaceView取得一个SurfaceHolder对象,可是如果要想实现拍照的功能,首先用户必须手动实现android.view. SurfaceHolder.Callback这个操作接口,在此接口中定义了高速图像浏览时的各个操作。
No.
方法
描述
1
Public abstract voidsurfaceChanged(SurfaceHolder holder,int format,int width,int height)
当预览界面的格式和大小发生改变时会触发此操作
2
Public abstract voidsurfaceCreated(SurfaceHolder holder)
当预览界面被创建时会触发此操作
3
Public abstract voidsurfaceDestroyed(SurfaceHolder holder)
当预览界面关闭时会触发此操作
         Android.hardware.Camera进行调用摄像头的操作类,此类主要负责完成拍照图片的参数设置及保存,需要注意的是摄像头只能被一个设备所支持。
Camera类中定义的内部接口:
No.
接口名称
描述
1
Android.hardware.Camera.AutoFocusCallback
自动对焦的回调操作
2
Android.hardware.Camera.ErrorCallback
错误出现时的回调操作
3
Android.hardware.Camera.OnZoomChangedListener
显示区域改变时的回调操作
4
Android.hardware.Camera.PictureCallback
图片生成时的回调操作
5
Android.hardware.Camera.PreviewCallback
预览时的回调操作
6
Android.hardware.Camera.ShutterCallback
按下快门后的回调操作
 
范例:预览,拍照
因为需要将照片保存在sdcard下,所以需要配置一些权限,同时将屏幕的方向设置为横屏
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.iflytek.demo"    android:versionCode="1"    android:versionName="1.0" >    <uses-sdk android:minSdkVersion="10" />    <application      android:icon="@drawable/ic_launcher"      android:label="@string/app_name" >      <activity            android:label="@string/app_name"            android:name=".CameraActivity"            android:screenOrientation="landscape" >            <intent-filter >                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>      </activity>    </application>    <uses-feature android:name="android.hardware.camera" />    <uses-feature android:name="android.hardware.camera.autofocus" />    <!-- 摄像头 -->    <uses-permission android:name="android.permission.CAMERA" />    <!-- SDCard权限 -->    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />    <!-- 写入扩展设备 -->    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /></manifest> main.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >    <Button      android:id="@+id/but"      android:layout_width="fill_parent"      android:layout_height="wrap_content"      android:text="照相" />    <SurfaceView      android:id="@+id/surface"      android:layout_width="fill_parent"      android:layout_height="fill_parent" /></LinearLayout>  
下面我们通过SurfaceView捕获图像,而后使用按钮进行图像的拍照。
现在必须将摄像头捕获到的内容设置到SurfaceView之中。
如果要想实现拍照的功能,那么前提一定是已经对焦成功。
CameraActivity.java
package com.iflytek.demo;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.text.MessageFormat;import java.util.List;import android.app.Activity;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.PixelFormat;import android.hardware.Camera;import android.hardware.Camera.AutoFocusCallback;import android.hardware.Camera.Parameters;import android.hardware.Camera.PictureCallback;import android.hardware.Camera.ShutterCallback;import android.os.Bundle;import android.os.Environment;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.Toast;public class CameraActivity extends Activity {private SurfaceView surfaceView = null;private Button btn = null;private SurfaceHolder surfaceHolder = null;private Camera camera = null;private boolean previewRunning = true;/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);this.btn = (Button) super.findViewById(R.id.but);this.surfaceView = (SurfaceView) super.findViewById(R.id.surface);this.surfaceHolder = this.surfaceView.getHolder();this.surfaceHolder.addCallback(new MySurfaceViewCallback());this.surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);this.surfaceHolder.setFixedSize(960, 640);this.btn.setOnClickListener(new OnClickListenerImpl());}private class OnClickListenerImpl implements OnClickListener {@Overridepublic void onClick(View v) {if (CameraActivity.this.camera != null) {// 实现自动对焦功能,这里最好不要写自动对焦的,否则可能会对焦不成功//CameraActivity.this.camera//.autoFocus(new AutoFocusCallbackImpl());CameraActivity.this.camera.takePicture(shutterCallback,pictureCallback, jpgCallback);}}}/** ** @author xdwang ** @create 2012-11-13 下午10:24:18 ** @email:xdwangiflytek@gmail.com ** @description 捕获屏幕 **/private class MySurfaceViewCallback implements SurfaceHolder.Callback {@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {}@Overridepublic void surfaceCreated(SurfaceHolder holder) {CameraActivity.this.camera = Camera.open(0); // 取得第一个摄像头,可能存在多个,0表示后面的,1表示前置摄像头Parameters parameters = CameraActivity.this.camera.getParameters();List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();Camera.Size pictureSize= previewSizes.get(0);parameters.setPreviewSize(pictureSize.width, pictureSize.height);//用以下方式会报:java.lang.RuntimeException: setParameters failed,因为不同手机的分辨率是不一样的//WindowManager manager = (WindowManager) CameraActivity.this.getSystemService(Context.WINDOW_SERVICE);//Display display = manager.getDefaultDisplay();//parameters.setPreviewSize(display.getWidth(), display.getHeight());// 设置预览大小,即手机屏幕大小parameters.setPreviewFrameRate(5); // 每秒5帧parameters.setPictureFormat(PixelFormat.JPEG); // 图片形式parameters.set("jpen-quality", 80);// 设置图片质量,最高100CameraActivity.this.camera.setParameters(parameters);try {CameraActivity.this.camera.setPreviewDisplay(CameraActivity.this.surfaceHolder);} catch (IOException e) {}CameraActivity.this.camera.startPreview(); // 进行预览CameraActivity.this.previewRunning = true; // 已经开始预览}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {if (CameraActivity.this.camera != null) {if (CameraActivity.this.previewRunning) {CameraActivity.this.camera.stopPreview(); // 停止预览CameraActivity.this.previewRunning = false;}CameraActivity.this.camera.release();}}}/** ** @author xdwang ** @create 2012-11-13 下午10:46:57 ** @email:xdwangiflytek@gmail.com ** @description 自动对焦 **/private class AutoFocusCallbackImpl implements AutoFocusCallback {@Overridepublic void onAutoFocus(boolean success, Camera camera) {if (success) { // 对焦成功CameraActivity.this.camera.takePicture(shutterCallback,pictureCallback, jpgCallback);}}}/** * 生成新的图片 */private PictureCallback jpgCallback = new PictureCallback() {@Overridepublic void onPictureTaken(byte[] data, Camera camera) { // 保存图片的操作// 所有的数据保存在byte数组中,将byte数组转换为BitmapBitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);String fullFileName = MessageFormat.format("{0}{1}xdwang{1}xdwang_{2}.jpg", Environment.getExternalStorageDirectory().toString(),File.separator, System.currentTimeMillis());File file = new File(fullFileName);if (!file.getParentFile().exists()) {file.getParentFile().mkdirs(); // 创建文件夹}try {BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));bitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos); // 向缓冲区之中压缩图片bos.flush();bos.close();Toast.makeText(CameraActivity.this,"拍照成功,照片已保存在" + fullFileName + "文件之中!",Toast.LENGTH_SHORT).show();} catch (Exception e) {Toast.makeText(CameraActivity.this, "拍照失败!", Toast.LENGTH_SHORT).show();}//为下一次拍照做准备CameraActivity.this.camera.stopPreview();CameraActivity.this.camera.startPreview();}};/** * 按下快门后的操作 */private ShutterCallback shutterCallback = new ShutterCallback() {@Overridepublic void onShutter() {// 按下快门之后进行的操作}};/** * 原始图像 */private PictureCallback pictureCallback = new PictureCallback() {@Overridepublic void onPictureTaken(byte[] data, Camera camera) {}};}  
二、多点触控
         多点触控指可以同事对用户的多个屏幕触摸点进行监听,并进行相应处理的一种操作,在Activity类中,使用onTouchEvent()方法完成多点触控,此方法定义如下:
Public Boolean onTouchEvent(MotionEventevent){}
         可以发现,在此方法中有一个android.view.MotionEvent类的时间对象,实际上用户可以通过该事件对象完成对多个触摸点的操作监听,而MotionEvent类的常用方法如下:
No.
方法
描述
1
Public final int getAction()
返回操作的Action类型,如按下or松开
2
Public final long getDownTimea()
返回按下的时间
3
Public final long getEventTime()
事件操作的结束时间
4
Public final int getPointerCount()
返回同时触摸点的个数
5
Public final float getX(int pointerIndex)
取得指定触摸点的X坐标
6
Public final float getY(intpointerIndex)
取得指定触摸点的Y坐标
 
比如完成图片的缩放操作:
package com.iflytek.demo;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Matrix;import android.graphics.Paint;import android.os.Bundle;import android.view.MotionEvent;import android.view.SurfaceHolder;import android.view.SurfaceView;public class MultitouchActivity extends Activity {private static final int SCALEBASIC = 3;// 调整的比率private int imageX = 0; // 计算图片的X轴private int imageY = 0; // 计算图片的Y轴private SurfaceHolder surfaceHolder = null;private int screenWidth = 0;private int screenHeight = 0;private int imageWidth = 0;private int imageHeight = 0;private Bitmap bitmap = null;/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);this.screenWidth = super.getWindowManager().getDefaultDisplay().getWidth();// 取得屏幕的宽度this.screenHeight = super.getWindowManager().getDefaultDisplay().getHeight();this.bitmap = BitmapFactory.decodeResource(super.getResources(),R.drawable.abc);this.imageWidth = this.bitmap.getWidth();this.imageHeight = this.bitmap.getHeight();this.imageX = (this.screenWidth - this.imageWidth) / 2;this.imageY = (this.screenHeight - this.imageHeight) / 2;super.setContentView(new MySurfaceView(this));// 使用SurfaceView封装}private class MySurfaceView extends SurfaceView implementsSurfaceHolder.Callback {public MySurfaceView(Context context) {super(context);MultitouchActivity.this.surfaceHolder = super.getHolder();MultitouchActivity.this.surfaceHolder.addCallback(this);// 添加Callback操作super.setFocusable(true); // 获得焦点,进行触摸事件}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {// SurfaceView改变}@Overridepublic void surfaceCreated(SurfaceHolder holder) {// SurfaceView创建MultitouchActivity.this.setImage(1.0f, 350, 500);// 设置默认显示图片}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {// 销毁}}/** * @descrption 设置图片 * @author xdwang * @create 2012-11-14下午8:08:41 * @param scale * @param width * @param height */private void setImage(float scale, int width, int height) { // 改变之后修改图片Canvas canvas = MultitouchActivity.this.surfaceHolder.lockCanvas(); // 获取画布Paint paint = new Paint();// 填充底色canvas.drawRect(0, 0, MultitouchActivity.this.screenWidth,MultitouchActivity.this.screenHeight, paint);// 绘制矩形Matrix matrix = new Matrix();// 控制图像matrix.postScale(scale, scale); // 缩放设置,等量缩放Bitmap target = Bitmap.createBitmap(MultitouchActivity.this.bitmap, 0,0, width, height, matrix, true);// 创建新图片this.imageWidth = target.getWidth(); // 取得新图片宽度this.imageHeight = target.getHeight();this.imageX = (this.screenWidth - this.imageWidth) / 2;// 重新计算X坐标this.imageY = (this.screenHeight - this.imageHeight) / 2;canvas.translate(this.imageX, this.imageY); // 图像平移,平移到指定的位置canvas.drawBitmap(this.bitmap, matrix, paint);// 重新绘图MultitouchActivity.this.surfaceHolder.unlockCanvasAndPost(canvas);// 解锁画布,并提交图象}/** * 触摸事件 */@Overridepublic boolean onTouchEvent(MotionEvent event) {int pointCount = event.getPointerCount();// 取得触控点数量if (pointCount == 2) {float pointA = event.getY(0);// 取得第一个触摸点的Y坐标float pointB = event.getY(1);// 取得第2个触摸点的Y坐标if (pointA < pointB) {// 让pointA保存最大点float temp = pointA;pointA = pointB;pointB = temp;}if (!(event.getAction() == MotionEvent.ACTION_UP)) {// 用户按下float scale = this.getScale(pointA, pointB) / SCALEBASIC;// 计算缩放量MultitouchActivity.this.setImage(scale, 350, 500);// 重设图片}}return super.onTouchEvent(event);}/** * @descrption 得到缩放比率 * @author xdwang * @create 2012-11-14下午8:15:25 * @param pointA * @param pointB * @return */private float getScale(float pointA, float pointB) {float scale = pointA / pointB;return scale;}} 
 
 
页: [1]
查看完整版本: Android学习11-----多媒体技术(4) 使用摄像头拍照,多点触控