相信通过上一篇博文大家已经熟悉了使用手机照相机的方法,在此基础上,我们通过添加额外的功能就可以开发出适合自己使用的自定义相机应用了,今天我们来完成照相机相片存储的实现。
还是你们喜欢的代码!!!
因为我们要在存储设备上进行读写操作,所以还是要先申请权限,在AndroidManifest.xml文件中增加如下代码:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
然后,我们来创建拍照界面布局,相比于上一个实例,我们这次再添加两个文本框,分别为重拍和保存,来实现我们先期望的功能:
/AndroidCamera01/res/layout/activity_main.xml
代码清单:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/Linear01"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<SurfaceView
android:id="@+id/surfCamera"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
<TextView
android:id="@+id/button_recamera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:text="重拍"
android:textColor="@android:color/white"
android:textSize="24dp"/>
<ImageButton
android:id="@+id/button_camera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:background="#00000000"
android:src="@drawable/button"/>
<TextView
android:id="@+id/button_save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:text="保存"
android:textColor="@android:color/white"
android:textSize="24dp"/>
</RelativeLayout>
最后,我们来编写最重要的MainActivity.java文件
/AndroidCamera01/src/com/example/androidcamera01/MainActivity.java
代码清单:
packagecom.example.androidcamera01;
importjava.io.ByteArrayOutputStream;
importjava.io.File;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.text.SimpleDateFormat;
importjava.util.Date;
importjava.util.List;
importandroid.annotation.SuppressLint;
importandroid.app.Activity;
importandroid.content.res.Configuration;
importandroid.graphics.Bitmap;
importandroid.graphics.BitmapFactory;
importandroid.hardware.Camera;
importandroid.hardware.Camera.PictureCallback;
importandroid.hardware.Camera.Size;
importandroid.os.Bundle;
importandroid.os.Environment;
importandroid.view.SurfaceHolder;
importandroid.view.SurfaceView;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.view.WindowManager;
importandroid.widget.ImageButton;
importandroid.widget.TextView;
importandroid.widget.Toast;
public classMainActivity extends Activity implements SurfaceHolder.Callback{
//拍照预览
private SurfaceView surfaceView;//定义视图控件
private SurfaceHolder surfaceHolder;//定义控件
//照相机
private Camera mCamera;
//图片地址
private ImageButton btn_camera;
private TextView btn_recamera;
private TextView btn_save;
private byte[] buffer = null;
public voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//设置布局
setContentView(R.layout.activity_main);
//禁止自动锁屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
//绑定视图
surfaceView =(SurfaceView) findViewById(R.id.surfCamera);
btn_camera =(ImageButton) findViewById(R.id.button_camera);
btn_save =(TextView) findViewById(R.id.button_save);
btn_recamera =(TextView) findViewById(R.id.button_recamera);
//从SurfaceView中获得SurfaceHolder
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
mCamera = isCameraAvailiable();
if(mCamera==null) Toast.makeText(getApplicationContext(),"相机设备被占用", Toast.LENGTH_SHORT).show();
//设置事件监听
surfaceCreated(surfaceHolder);
ButtonOnClickListener onClickListener = newButtonOnClickListener();
btn_recamera.setOnClickListener(onClickListener);
btn_camera.setOnClickListener(onClickListener);
btn_save.setOnClickListener(onClickListener);
}//end of onCreate
//判断照相机设备是否可用
public static CameraisCameraAvailiable(){
Camera object = null;
try {
object = Camera.open();
}
catch(Exception e){
}
return object;
}
class ButtonOnClickListener implementsOnClickListener{
@Override
public voidonClick(View v) {
// TODOAuto-generated method stub
switch (v.getId()){
case R.id.button_camera: {
mCamera.takePicture(null, null, capturedIt);
btn_camera.setVisibility(View.INVISIBLE);
btn_recamera.setVisibility(View.VISIBLE);
btn_save.setVisibility(View.VISIBLE);
break;}
case R.id.button_recamera:{
mCamera.startPreview();
btn_camera.setVisibility(View.VISIBLE);
btn_recamera.setVisibility(View.INVISIBLE);
btn_save.setVisibility(View.INVISIBLE);
break;
}
case R.id.button_save:{
saveImageToFile();
btn_camera.setVisibility(View.INVISIBLE);
btn_recamera.setVisibility(View.VISIBLE);
btn_save.setVisibility(View.INVISIBLE);
break;
}
}
}
}//end ofclass ButtonOnClickListener
//picture显示
private PictureCallback capturedIt = newPictureCallback() {
@Override
public voidonPictureTaken(byte[] data, Camera camera) {
Bitmap bitmap = BitmapFactory.decodeByteArray(data , 0, data .length);
if(bitmap==null){
}
else
{ ByteArrayOutputStream baos = newByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
buffer = new byte[baos.toByteArray().length];
buffer = baos.toByteArray().clone();}
}
};//end ofclass PictureCallback
private voidsaveImageToFile(){
File file = getOutFile();
if (file == null){
Toast.makeText(getApplicationContext(), "文件创建失败,请检查SD卡读写权限", Toast.LENGTH_SHORT).show();
return ;
}
if (buffer == null){
}else{
try{
FileOutputStream fos = newFileOutputStream(file);
fos.write(buffer);
fos.flush();
fos.close();
}catch(IOException e){
e.printStackTrace();
}
}
}//end ofsaveImageToFile
private File getOutFile() {
// TODOAuto-generated method stub
String storageState = Environment.getExternalStorageState();
if(Environment.MEDIA_REMOVED.equals(storageState)){
Toast.makeText(getApplicationContext(), "oh,no, SD卡不存在", Toast.LENGTH_SHORT).show();
return null;
}
File mediaStorageDir = new File(Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
,"MyPictures");
if (!mediaStorageDir.exists()){
if (!mediaStorageDir.mkdirs()){
return null;
}
}
File file = new File(setFilePath(mediaStorageDir));
return file;
}//end of getOutFile
@SuppressLint("SimpleDateFormat")
private StringsetFilePath(File mediaStorageDir) {
// TODOAuto-generated method stub
String timeStamp =newSimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String filePath = mediaStorageDir.getPath()+ File.separator;
filePath += (timeStamp + ".jpg");
return filePath;
}//end of getFilePath
@Override
public voidsurfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
/************************************************************
* 目前只考虑到竖屏使用的情况,所以这一部分不用写,当想加入横屏时须在此处配置参数
*/
}
@Override
public voidsurfaceCreated(SurfaceHolder holder) {
try {
Camera.Parameters parameters = mCamera.getParameters();
if(this.getResources().getConfiguration().orientation!=Configuration.ORIENTATION_LANDSCAPE)
{
parameters.set("orientation", "portrait");
mCamera.setDisplayOrientation(90);
parameters.setRotation(90);
}else {
parameters.set("orientation", "landscape");
//对于Android 2.2及以上版本
mCamera.setDisplayOrientation(0);
//对于Android2.2及以上版本取消注释
parameters.setRotation(0);
}
Size largestSize =getBestSupportedSize(parameters.getSupportedPreviewSizes());
parameters.setPreviewSize(largestSize.width, largestSize.height);// 设置预览图片尺寸
parameters.setPictureSize(largestSize.width, largestSize.height);
mCamera.setParameters(parameters);
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
System.out.println("startPreview");
} catch (IOException e) {
mCamera.release();
}
}
@Override
public voidsurfaceDestroyed(SurfaceHolder arg0) {
mCamera.stopPreview();
mCamera.release();
}
private SizegetBestSupportedSize(List<Size> sizes) {
// 取能适用的最大的SIZE
Size largestSize = sizes.get(0);
int largestArea = sizes.get(0).height * sizes.get(0).width;
for (Size s : sizes) {
int area = s.width * s.height;
if (area > largestArea) {
largestArea = area;
largestSize = s;
}
}
return largestSize;
}
}
有保存图片功能的相机很明显,从字面上我们就知道应该添加保存图片的功能,相比于上一个简单的相机的代码,这个实例的代码增加的部分主要是:
1. 按键的监听和处理;
本开发案例要实现拍照功能,保存图片的功能,以及保存后在进入拍照状态。所以我们在界面中添加了三个按钮,对这三个事件源添加事件监听从而实现我们想要的功能。这部分内容是Android开发的基础,再次不做赘述。
2. 实现PictureCallback接口,重写onPictureTaken方法:
这里引入了BitMap类,Bitmap是Android系统中的图像处理的最重要类之一。用它可以获取图像文件信息,进行图像剪切、旋转、缩放等操作,并可以指定格式保存图像文件。
更多介绍请参见文档
http://www.open-open.com/lib/view/open1333418945202.html
public voidonPictureTaken(byte[] data, Camera camera) {
//将频幕当前图像转换成Bitmap对象
Bitmap bitmap =BitmapFactory.decodeByteArray(data , 0, data .length);
//字节输出流,用于存放图片字节流
ByteArrayOutputStream baos = newByteArrayOutputStream();
//输出格式设置
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
//第你一一片缓存区,存储图片,用于预览
buffer = new byte[baos.toByteArray().length];
buffer = baos.toByteArray().clone();}
}
3. 存储文件
这部分就涉及到Android开放当中文件操作的部分了,在这里我们用了两个方法完成了设置存储文件的名称,存储路径,将文件存储到设置好的路径下:
private voidsaveImageToFile(){… …}
private File getOutFile() {… …}
文件读写部分我会在Android开发文件操作部分进行详细说明的部分。
效果图: