`

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

阅读更多

一、摄像头拍照

前面说媒体播放 时了解了 SurfaceView 最大的特点就是提供了一个高速的更新空间,那么如果说现在要进行图像的捕获,那么肯定要跟随摄像头一起变化,那么这块空间很明显必须使用高速的刷新频率。

         使用 SurfaceView 组件可以进行视频文件的播放,而同样可以继续利用 SurfaceView 实现拍照的浏览功能,在支持拍照的手机上,都会为用户提供一个预览的屏幕显示当前摄像头所采集到的图片,而这种功能可以利用 SurfaceView 实现, SurfaceView 之中的操作核心就是在于 android.view. SurfaceHolder 对象的操作,前面说了可以通过 SurfaceView 取得一个 SurfaceHolder 对象,可是如果要想实现拍照的功能,首先用户必须手动实现 android.view. SurfaceHolder.Callback 这个操作接口,在此接口中定义了高速图像浏览时的各个操作。

No.

方法

描述

1

Public abstract void surfaceChanged(SurfaceHolder holder,int format,int width,int height)

当预览界面的格式和大小发生改变时会触发此操作

2

Public abstract void surfaceCreated(SurfaceHolder holder)

当预览界面被创建时会触发此操作

3

Public abstract void surfaceDestroyed(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. */
	@Override
	public 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 {

		@Override
		public 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 {

		@Override
		public void surfaceChanged(SurfaceHolder holder, int format, int width,
				int height) {

		}

		@Override
		public 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);// 设置图片质量,最高100
			CameraActivity.this.camera.setParameters(parameters);
			try {
				CameraActivity.this.camera
						.setPreviewDisplay(CameraActivity.this.surfaceHolder);
			} catch (IOException e) {
			}
			CameraActivity.this.camera.startPreview(); // 进行预览
			CameraActivity.this.previewRunning = true; // 已经开始预览
		}

		@Override
		public 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 {

		@Override
		public void onAutoFocus(boolean success, Camera camera) {
			if (success) { // 对焦成功
				CameraActivity.this.camera.takePicture(shutterCallback,
						pictureCallback, jpgCallback);
			}
		}

	}

	/**
	 * 生成新的图片
	 */
	private PictureCallback jpgCallback = new PictureCallback() {

		@Override
		public void onPictureTaken(byte[] data, Camera camera) { // 保存图片的操作
			// 所有的数据保存在byte数组中,将byte数组转换为Bitmap
			Bitmap 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() {
		@Override
		public void onShutter() {
			// 按下快门之后进行的操作
		}
	};

	/**
	 * 原始图像
	 */
	private PictureCallback pictureCallback = new PictureCallback() {

		@Override
		public void onPictureTaken(byte[] data, Camera camera) {

		}

	};
}
 

 

二、多点触控

         多点触控指可以同事对用户的多个屏幕触摸点进行监听,并进行相应处理的一种操作,在 Activity 类中,使用 onTouchEvent() 方法完成多点触控,此方法定义如下:

Public Boolean onTouchEvent(MotionEvent event){}

         可以发现,在此方法中有一个 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. */
	@Override
	public 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 implements
			SurfaceHolder.Callback {

		public MySurfaceView(Context context) {
			super(context);
			MultitouchActivity.this.surfaceHolder = super.getHolder();
			MultitouchActivity.this.surfaceHolder.addCallback(this);// 添加Callback操作
			super.setFocusable(true); // 获得焦点,进行触摸事件
		}

		@Override
		public void surfaceChanged(SurfaceHolder holder, int format, int width,
				int height) {// SurfaceView改变

		}

		@Override
		public void surfaceCreated(SurfaceHolder holder) {// SurfaceView创建
			MultitouchActivity.this.setImage(1.0f, 350, 500);// 设置默认显示图片
		}

		@Override
		public 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);// 解锁画布,并提交图象
	}

	/**
	 * 触摸事件
	 */
	@Override
	public 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;
	}
}

 

 

 

分享到:
评论

相关推荐

    Android手势识别-多点触控

    在Android平台上,手势识别与多点触控是移动应用开发中的关键组成部分,它们极大地提升了用户交互体验。Android系统提供了一套强大的API,使得开发者能够轻松地处理和解析用户的触摸事件,进而实现各种复杂的手势...

    行业分类-设备装置-多点触控的多媒体球幕演示仪及其多点触控方法.zip

    标题中的“行业分类-设备装置-多点触控的多媒体球幕演示仪及其多点触控方法”揭示了我们讨论的核心技术领域,即多点触控技术在多媒体球幕演示设备上的应用。这类设备通常用于展示高清晰度的影像、三维动画或科学模拟...

    android小程序-电子钢琴-多点触控

    在本项目中,我们探索的是一个Android小程序,它是一个电子钢琴应用,支持多点触控功能,从而允许用户同时按下多个琴键,创造出更...希望这个项目能帮助你进一步了解Android编程以及多点触控技术在移动应用中的应用。

    Android高级应用源码-多点触控控制字体大小,源码中有详细注释,简单Demo.zip

    在Android开发中,实现多点触控控制字体大小是一项高级技术,这通常涉及到手势识别、事件处理以及UI动态更新等多个方面。本示例项目“Android高级应用源码-多点触控控制字体大小”提供了一个详细的参考实现,帮助...

    Android多点触控技术实战,对图片进行缩放和移动Demo

    在Android开发中,多点触控(Multi-Touch)技术是一项关键特性,它允许用户通过两个或更多手指来与屏幕交互,实现如缩放、旋转、拖动等操作。本项目"PhotoWallFallsDemo"就是一个典型的实例,演示了如何在Android...

    flash as3 多点触控-缩放-旋转-滑动.zip

    在IT行业中,多点触控技术是用户界面交互的一个重要组成部分,尤其是在移动设备和触摸屏应用上。Flash AS3(ActionScript 3)是Adobe Flash Professional用于创建动态内容、交互式应用程序和游戏的主要编程语言。在...

    Android 多点触控实例--图片的缩放

    在Android开发中,多点触控(Multi-Touch)是一项重要的功能,允许用户通过两个或更多的手指进行交互,如缩放、旋转等操作。本文将深入探讨如何在Android应用程序中实现图片的多点触控缩放功能。我们将讨论以下几个...

    Android代码-多点触控实例源码.zip

    本实例源码是针对Android开发的多点触控功能的实现,通过分析和学习,开发者可以掌握如何在自己的应用程序中集成多点触控功能。 1. 多点触控基础 在Android中,多点触控主要通过`MotionEvent`类来实现。`...

    AutoJs源码-教程-多点触控(6)

    AutoJs源码-教程_多点触控(6)。本资源购买前提醒:本源码都是实际autojs项目模板,安装好autojs直接运行即可打开。1、支持低版本autojs。2、资源仅供学习与参考,请勿用于商业用途,否则产生的一切后果将由您自己...

    Android 多点触控实例源码-IT计算机-毕业设计.zip

    这个名为"Android 多点触控实例源码"的压缩包提供了实现这一功能的源代码,对于学习和理解Android多点触控编程具有极大的帮助。 1. **Android多点触控基础** - 触摸事件:Android系统通过`MotionEvent`类处理触摸...

    android多点触控demo,两只手同时拖拽

    在Android开发中,多点触控(Multitouch)是一项重要的功能,允许用户通过两个或更多的手指进行交互,如缩放、旋转、平移等操作。这个"android多点触控demo,两只手同时拖拽"是针对Android平台的一个示例项目,其...

    AutoJs源码-教程-多点触控

    AutoJs源码-教程_多点触控。本资源购买前提醒:本源码都是实际autojs项目模板,安装好autojs直接运行即可打开。1、支持低版本autojs。2、资源仅供学习与参考,请勿用于商业用途,否则产生的一切后果将由您自己承担!...

    Android安卓源码-多点触控&手势操作类源代码(5例).zip

    这个压缩包提供了五个不同的示例,旨在帮助开发者深入理解和实践Android中的多点触控和手势识别技术。 1. **多点触控(Multi-Touch)**: 多点触控允许用户通过同时触摸屏幕的多个点来与应用进行交互。在Android中...

    最简单android 多点触控 图片放大

    在Android开发中,实现多点触控功能可以让用户更加自然地与应用进行交互,特别是对于图片查看、手势操作等场景非常实用。本教程将详细讲解如何实现一个最简单的Android多点触控图片放大功能,无需复杂的代码,主要...

    BLE_HID_arduinoBLE多点触控_

    总的来说,"BLE_HID_arduinoBLE多点触控"项目结合了物联网、嵌入式系统、无线通信和多点触控技术,提供了一种创新的交互方式,不仅适用于学习和探索,也对实际应用有着广阔的前景。通过不断的调试和完善,可以实现更...

    安卓Android源码——多点触控实例源码.zip

    在安卓(Android)平台上,开发多点触控功能是实现用户交互的重要部分,尤其是在创建复杂的触摸界面时。这个“安卓Android源码——多点触控实例源码.zip”压缩包包含了一个具体的多点触控应用的源代码,可以帮助...

    Android开发实战经典-031008-多点触控视频教程.zip

    Android开发实战经典_031008_多点触控视频教程.zip

    Android 多点触控实例源码.rar

    这个"Android多点触控实例源码"提供了一个实用的学习资源,帮助开发者深入理解并实践Android中的多点触控技术。以下将详细介绍该源码中的关键知识点。 1. **MotionEvent**:在Android中,处理触摸事件的核心类是`...

    安卓多点触控手势操作相关-Android手势调节音量亮度进度.rar

    "Android手势调节音量,亮度,进度"这个项目涵盖了Android开发中的多点触控手势识别、系统资源控制(音量、亮度)、UI组件(如SeekBar)的使用以及程序调试等多个知识点,为Android开发者提供了一个实用的学习案例。

    多点触控事例

    多点触控技术是现代电子设备中不可或缺的一部分,尤其在智能手机、平板电脑和触摸屏显示器等领域广泛应用。这种技术允许用户通过同时使用一个或多个手指来与屏幕进行交互,提供了更为直观和自然的操作体验。本文将...

Global site tag (gtag.js) - Google Analytics