您的位置:首页 > 移动开发 > 微信开发

使用Android开发照相功能小程序实例

2015-07-22 18:24 871 查看
主要实现拍照功能的类:Camera类。功能描述:首先进入拍照界面,点击拍照按钮,转跳(使用到Intent类实现Activity之间转跳)到拍照预览模式界面,点击拍照按钮,进行拍照,拍照的照片存放到指定的文件夹中的功能。

下面通过Samples_10_4程序具体实现功能:

(1)新建一个Android Application Project项目取名为Samples_10_4

(2)在res/layout文件修改activity_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">

<TextView

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="@string/hello"/>

<Button

android:id="@+id/camera_button"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:text="拍照"/>

</LinearLayout>



(3)因为要实现拍照的功能,在res/layout目录下添加camera.xml布局文件(主要包括SurfaceView控件和拍照按钮)具体SurfaceView的具体功能在我的博客里有详细介绍:Android
surfaceview详解:


<?xml
version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

android:id="@+id/linearLayout01">

<SurfaceView

android:id="@+id/camera_surface"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:layout_weight="1">

</SurfaceView>

<Button

android:id="@+id/take"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:text="拍照"/>

</LinearLayout>



(4)首先需要给程序必要的权限才能读/写、访问Camera、创建删除文件等权限。在程序的AndroidManifest.xml程序清单文件下添加如下权限:


<!-- 访问Camera权限 -->



<uses-permission android:name="android.permission.CAMERA" />



<!-- 在SDCard中创建与删除文件权限 -->



<uses-permission android:name="android.permission.WRITE_SETTINGS" />

<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />

<!-- 往SDCard写入数据权限 -->

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />



因为因为TakeCamera.java类是另一个Activity所以还需要在AndroidMainifest.xml文件中添加这样一段代码(一般这里的类名需要写完整的类结构):

<activity android:name=".TakeCamera"></activity>



(5)下面就是两个Activity实现布局文件调用和具体功能的实现:MainActivity.java类(拍照主界面)和TakeCamera类(拍照功能):



A.MainActivity.java类的具体实现:



package
com.example.samples_10_4;

import android.os.Bundle;

import android.app.Activity;

import android.view.Menu;

import android.widget.Button;

import android.view.View;

import android.content.Intent;

public class MainActivity extends Activity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

Button button=(Button)this.findViewById(R.id.camera_button);
//实例化Button组件对象

button.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View arg0) {

// 为Button添加单击监听事件

Intent intent=new Intent();

intent.setClass(MainActivity.this, TakeCamera.class);
//指定intent对象启动的类

MainActivity.this.startActivity(intent);
//启动新的Activity

}

});

}

@Override

public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.

getMenuInflater().inflate(R.menu.main, menu);

return true;

}

}



B.TakeCamera类的具体实现:



package
com.example.samples_10_4;

import android.app.Activity;

import android.view.SurfaceHolder;

import android.widget.Button;

import android.view.SurfaceView;

import android.hardware.Camera;

import android.os.Bundle;

import android.graphics.PixelFormat;

import android.view.Window;

import android.view.WindowManager;

import android.content.pm.ActivityInfo;

import android.view.View;

import android.hardware.Camera.ShutterCallback;

import android.hardware.Camera.PictureCallback;

import android.os.Environment;

import java.io.File;

import android.text.format.DateFormat;

import java.util.Date;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import java.io.BufferedOutputStream;

import java.io.FileOutputStream;

import java.util.Timer;

import android.os.Handler;

import android.os.Message;

import java.io.IOException;

import android.graphics.PixelFormat;

import java.util.TimerTask;

import android.view.KeyEvent;

public class TakeCamera extends Activity implements SurfaceHolder.Callback {

private Button btn_take;
//创建一个Button控件对象

private SurfaceView surfaceView=null;
//创建一个空的SurfaceView控件对象

private SurfaceHolder surfaceHolder=null;
//创建一个SurfaceHolder控件对象

private Camera camera=null;
//创建一个空的Camera对象

private boolean previewRunning=false;
//预览状态

@Override

public void onCreate(Bundle savedInstanceState)

{

super.onCreate(savedInstanceState);

this.getWindow().setFormat(PixelFormat.TRANSLUCENT);
//窗口设置为半透明

this.requestWindowFeature(Window.FEATURE_NO_TITLE);
//窗口去掉标题

this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,

WindowManager.LayoutParams.FLAG_FULLSCREEN);
//窗口设置为全屏

this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// 调用setRequestedOrientation来翻转Preview

this.setContentView(R.layout.camera);

surfaceView=(SurfaceView)this.findViewById(R.id.camera_surface);
//实例化SurfaceView对象

surfaceHolder=surfaceView.getHolder();
//获取SurfaceHolder

surfaceHolder.addCallback(this);

surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
//设置缓存类型

btn_take=(Button)this.findViewById(R.id.take);

btn_take.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

if(camera!=null)
//判断Camera对象是否为空

{

//当按下按钮时,执行相机对象的takePicture()方法,该方法有三个回调函数作为入参,不需要时可以设为null

camera.takePicture(null, null, jpegCallback);

changeByTime(5000);
//调用延迟方法,5秒后重新预览拍照

}

}

});

}

/**

* 延迟方法

* @param time 毫秒

*/

public void changeByTime(long time)

{

final Timer timer=new Timer();

final Handler handle=new Handler()

{

@Override

public void handleMessage(Message msg)

{

switch(msg.what)

{

case 1:

stopCamera();
//停止Camera方法

pepareCamera();
//调用初始化Camera方法

startCamera();
//调用开始Camera

timer.cancel();
//撤销计时器

break;

default:

break;

}

super.handleMessage(msg);

}

};

TimerTask task=new TimerTask()

{

@Override

public void run()

{

Message message=new Message();

message.what=1;

handle.sendMessage(message);

}

};

timer.schedule(task, time);
//每隔time时间执行TimerTash类中的Run方法

}

@Override

public boolean onKeyDown(int keyCode,KeyEvent event)

{

//判断手机按键按下的是否是拍照键或者轨迹球键

if(keyCode==KeyEvent.KEYCODE_CAMERA||keyCode==KeyEvent.KEYCODE_DPAD_CENTER)

{

if(camera!=null)

{

//当按下按钮时,执行相机对象的takePicture()方法,该方法有三个回调函数作为入参,不需要时可以设为null

camera.takePicture(null, null, jpegCallback);

changeByTime(5000);
//调用延迟方法,5秒后重新预览拍照

}

}

return super.onKeyDown(keyCode, event);

}

/**

* 开始Camera

*/

public void startCamera()

{

if(previewRunning)
//判断预览开启

{

camera.stopPreview();
//停止预览

}

try

{

Camera.Parameters parameters=camera.getParameters();
//获取相机参数对象

parameters.setPictureFormat(PixelFormat.JPEG);
//设置格式

//设置预览大小

parameters.setPreviewSize(480, 320);

//设置自动对焦

parameters.setFocusMode("auto");

//设置图片保存时的分辨率大小

parameters.setPictureSize(2048, 1536);

camera.setParameters(parameters);
//给相机对象设置刚才设定的参数

camera.setPreviewDisplay(surfaceHolder);
//设置用SurfaceView作为承载镜头取景画面的显示

camera.startPreview();
//开始预览

previewRunning=true;
//设置预览状态为true

}catch(IOException e)

{

e.printStackTrace();

}

}

/**

* 初始化Camera

*/

public void pepareCamera()

{

camera=Camera.open();
//初始化Camera

try

{

camera.setPreviewDisplay(surfaceHolder);
//设置预览

}catch(IOException e)

{

camera.release();
//释放相机资源

camera=null;
//置空Camera对象

}

}

/**

* 停止Camera

*/

public void stopCamera()
//判断Camera对象不为空

{

if(camera!=null)

{

camera.stopPreview();
//停止预览

camera.release();
//释放摄像头资源

camera=null;
//置空Camera对象

previewRunning=false;
//设置预览状态为false

}

}

/**

* 拍摄之后的事件

*/

private PictureCallback jpegCallback=new PictureCallback()

{ //拍照时调用

@Override

public void onPictureTaken(byte[] arg0,Camera arg1)

{

//获取SD卡的根目录

String sdCard=Environment.getExternalStorageDirectory().getPath();

//获取相片存放位置目录

String dirFilePath=sdCard+File.separator+"MyCamera";

//获取当期时间的自定义字符串

String date=DateFormat.format("yyyy-MM-dd hh-mm-ss",new Date()).toString();

//onPictureTaken传入的第一个参数即为图片的byte,实例化BitMap对象

Bitmap bitMap=BitmapFactory.decodeByteArray(arg0, 0, arg0.length);

try

{

//创建相片存放位置的File对象

File dirFile=new File(dirFilePath);

if(!dirFile.exists())

{

dirFile.mkdir();
//创建文件夹

}

//文件的格式

//创建一个前缀为photo,后缀为.jpg的图片文件,CreateTempFile是为了避免重复冲突

File file=File.createTempFile("photo-", ".jpg",dirFile);

BufferedOutputStream bOutputStream=new BufferedOutputStream(new FileOutputStream(file));

//采用压缩文件的方法

bitMap.compress(Bitmap.CompressFormat.JPEG, 80, bOutputStream);

//清除缓存,更新BufferedOutputStream

bOutputStream.flush();

//关闭BufferedOutputStream

bOutputStream.close();

}catch(Exception e)

{

e.printStackTrace();

}

}

};

/**

* 初次实例化,预览界面被创建时,该方法被调用

*/

public void surfaceCreated(SurfaceHolder arg0)

{

pepareCamera();
//调用初始化Camera

}

/**

* 当预览的格式和大小发生改变时,该方法被调用

*/

public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3)

{

startCamera();
//调用开始Camera方法

}

/**

* 预览界面被关闭该方法被调用

*/

public void surfaceDestroyed(SurfaceHolder arg0)

{

stopCamera();
//调用停止Camera方法

}

}



(6)程序运行的结果如图所示:



A.进入主界面:






B.在主界面中点击拍照按钮:






C.点击拍照按钮之后图片会创建一个MyCamera目录:






D.MyCamera目录下存放刚拍摄的图片:






E.刚拍的照片:






(7)代码程序具体详解:

MainActivity.java和TakeCamera.java之间通过Intent进行数据传递和页面的转跳:

Intent intent=new Intent();

intent.setClass(MainActivity.this, TakeCamera.class);
//指定intent对象启动的类

MainActivity.this.startActivity(intent);
//启动新的Activity



TakeCamera类实现了SurfaceHolder.Callback接口,需要实现三个surfaceCreated/Changed/Destroyed方法,从字面上可以看出主要是对界面绘制过程中内存操作的生命周期。

public class TakeCamera extends Activity implements
SurfaceHolder.Callback



使用了Timer类来实现拍照延时的功能:

Timer类调用schedule方法两个参数一个是TimerTask类(在每个延时的时间里TimerTask中Run()方法执行的相应次),另一个是延时的时间毫秒为单位。

使用Activity的onKeyDown方法用于在Activity下按下拍照键和确认键执行拍照的功能。

public boolean onKeyDown(int keyCode,KeyEvent event)



预览模式主要用于拍照时取景的功能。在预览之前需要获取相机的一些参数用于拍照服务,比如相机的预览大小、相机的对焦、图片保存的分辨率等等。

Camera.Parameters parameters=camera.getParameters();
//获取相机参数对象

parameters.setPictureFormat(PixelFormat.JPEG);
//设置格式

//设置预览大小

parameters.setPreviewSize(480, 320);

//设置自动对焦

parameters.setFocusMode("auto");

//设置图片保存时的分辨率大小

parameters.setPictureSize(2048, 1536);

camera.setParameters(parameters);
//给相机对象设置刚才设定的参数

camera.setPreviewDisplay(surfaceHolder);
//设置用SurfaceView作为承载镜头取景画面的显示

camera.startPreview();
//开始预览

previewRunning=true;
//设置预览状态为true



拍照时需要提供回调函数,主要用于指定存储路径或创建存储目录(采用了输出数据流和缓存输出流以及二进制图片压缩)

private PictureCallback jpegCallback=new PictureCallback()



//拍照时调用

@Override

public void onPictureTaken(byte[] arg0,Camera arg1)

{

//获取SD卡的根目录

String sdCard=Environment.getExternalStorageDirectory().getPath();

//获取相片存放位置目录

String dirFilePath=sdCard+File.separator+"MyCamera";

//获取当期时间的自定义字符串

String date=DateFormat.format("yyyy-MM-dd hh-mm-ss",new Date()).toString();

//onPictureTaken传入的第一个参数即为图片的byte,实例化BitMap对象

Bitmap bitMap=BitmapFactory.decodeByteArray(arg0, 0, arg0.length);

try

{

//创建相片存放位置的File对象

File dirFile=new File(dirFilePath);

if(!dirFile.exists())

{

dirFile.mkdir();
//创建文件夹

}

//文件的格式

//创建一个前缀为photo,后缀为.jpg的图片文件,CreateTempFile是为了避免重复冲突

File file=File.createTempFile("photo-", ".jpg",dirFile);

BufferedOutputStream bOutputStream=new BufferedOutputStream(new FileOutputStream(file));

//采用压缩文件的方法

bitMap.compress(Bitmap.CompressFormat.JPEG, 80, bOutputStream);

//清除缓存,更新BufferedOutputStream

bOutputStream.flush();

//关闭BufferedOutputStream

bOutputStream.close();

}catch(Exception e)

{

e.printStackTrace();

}

}



至此所有的拍照功能都已经介绍完成了,需要注意信息传递问题和访问权限问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: