当前位置: 代码迷 >> Android >> 使用Android开发拍照功能小程序实例
  详细解决方案

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

热度:36   发布时间:2016-04-27 23:51:46.0
使用Android开发照相功能小程序实例

主要实现拍照功能的类: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 implementsSurfaceHolder.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();
}
}


至此所有的拍照功能都已经介绍完成了,需要注意信息传递问题和访问权限问题。


版权声明:本文为博主原创文章,未经博主允许不得转载。

  相关解决方案