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

Android摄像头基础——第二阶段 自定义简单的相机

2016-01-20 22:25 666 查看


一、

1.布局文件

<?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" >

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/startCamera"
android:text="Start Camera"/>

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/startCamera2"
android:text="Start Camera2"/>

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/customCamera"
android:text="Custom Camera"/>

<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/imageView" />

</LinearLayout>


增加了一个按钮,点击之后进入自定义相机界面

2.MainActivity.java

public class MainActivity extends Activity {
private Button startCamera;
private Button startCamera2;
private Button customCamera;
private ImageView imageView;

private String photoFilePath;// 照片存放路径

private static final int REQ_1 = 1;
private static final int REQ_2 = 2;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startCamera = (Button) findViewById(R.id.startCamera);
startCamera2 = (Button) findViewById(R.id.startCamera2);
customCamera=(Button) findViewById(R.id.customCamera);
imageView = (ImageView) findViewById(R.id.imageView);
photoFilePath = Environment.getExternalStorageDirectory().getPath();// 获取sd卡目录的路径
photoFilePath += "/test.jpg";
startCamera.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);// 指定action,隐式Intent
startActivityForResult(intent, REQ_1);// 在指定的新的Activity结束后返回此Activity中,并且返回了数据
// REQ_1相当于一个标记,当时指定的Activity结束后会返回REQ_1给onActivityResult中的requestCode
// 表明是需要的Activity返回的数据
}
});

startCamera2.setOnClickListener(new OnClickListener() {
// 从照片存储的系统目录中去获取原图
@Override
public void onClick(View v) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri photoUri = Uri.fromFile(new File(photoFilePath));// 这里包含两步
// 首先根据指定路径创建一个文件对象
// 然后根据这个文件对象获得Uri
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);// 根据EXTRA_OUTPUT参数,系统相机将会在获取照片后根据相应的Uri存储照片
// 一定要注意,是uri,不是文件的路径字符串!!!!!!!!!!

startActivityForResult(intent, REQ_2);
}
});

customCamera.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
//注意:这儿不能直接用intent(this,XXX.class),因为这是在一个匿名类中,如果直接this就是指的当前的匿名类,而非MainActivity.this
startActivity(new Intent(MainActivity.this,CustomCamera.class));
}
});
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {// 判断新启动的Activity是否顺利结束
if (requestCode == REQ_1) {
Bundle bundle = data.getExtras();// Bundle类是一个key-value对,两个activity之间的通讯可以通过bundle类来实现
// data中的图片数据是缩略图,而不是原图(因此imageView中显示的图片不会像原图那样清晰)
// 因为如果返回原图可能会数据量太大导致数据溢出

// Bitmap是Android系统中的图像处理的最重要类之一
Bitmap bitmap = (Bitmap) bundle.get("data");// 将得到的图片数据存储在bitmap中

if(bitmap!=null) startCamera.setText(""+bitmap.getWidth()+" "+bitmap.getHeight());
else startCamera.setText("null");

imageView.setImageBitmap(bitmap);
} else if (requestCode == REQ_2) {
FileInputStream fis = null;// 局部变量需要初始化
try {
fis = new FileInputStream(photoFilePath);

Bitmap bitmap = BitmapFactory.decodeStream(fis);
//在第一阶段中,有提过关于图片尺寸过大而引起的问题,需要注意一下

if(bitmap!=null) startCamera2.setText(""+bitmap.getWidth()+" "+bitmap.getHeight());
else startCamera2.setText("null");

imageView.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}


二、实现自定义的相机

1.布局文件

<?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" >

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/customButton"
android:text="CAPTURE"/>

<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content" >

<!-- SurfaceView用来预览相机的取景 -->
<SurfaceView
android:id="@+id/preview"
android:layout_width="match_parent"
android:layout_height="match_parent" />

<!-- 在预览界面上增加水印 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="Welcome to my camera"
android:textColor="#ea3826"
android:textSize="20sp"
android:layout_marginBottom="72dp" />

</RelativeLayout>

</LinearLayout>


2.CustomCamera.java

/**
* 实现自定义相机的核心类
* 1 实现相机的三个生命周期方法getCamera、setStartPreview、releaseCamera(这三个方法基本是固定的),
*   并且与之和Activity的生命周期绑定起来
* 2 实现SurfaceHolder.Callback接口(因为在布局文件中使用了SurfaceView),
*   注意要在getCamera和releaseCamera方法中分别将Camera对象与布局文件中的SurfaceView进行绑定与取消绑定
* (以上两布都是对相机的生命周期进行管理)
* 3 实现点击按钮进行拍照的功能,设置拍照时的参数以及实现AutoFocusCallback接口中onAutoFocus方法的第三个参数(一个回调接口)
*
*/
public class CustomCamera extends Activity implements SurfaceHolder.Callback {
private Button customButton;
private Camera mCamera;
private SurfaceView mPreview;//用来预览相机的取景
private SurfaceHolder mHolder;
private PictureCallback mPictureCallback = new PictureCallback() {

@Override
public void onPictureTaken(byte[] data, Camera camera) {
//data保存了拍照之后整个照片完整的数据(而非缩略图的数据)
//          File tempFile=new File("/sdcard/temp.png");//创建一个临时文件用来保存照片,可以自定义其路径
File tempFile=new File("/storage/emulated/0/temp.png");
try {
FileOutputStream fos=new FileOutputStream(tempFile);
fos.write(data);
fos.close();
Intent intent=new Intent(CustomCamera.this,Result.class);
intent.putExtra("picPath", tempFile.getAbsolutePath());
startActivity(intent);
CustomCamera.this.finish();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.custom);
customButton = (Button) findViewById(R.id.customButton);
mPreview = (SurfaceView) findViewById(R.id.preview);
mPreview.setOnClickListener(new OnClickListener() {
// 实现点击SurfaceView范围内的屏幕时自动对焦
@Override
public void onClick(View v) {
mCamera.autoFocus(null);
}
});
customButton.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
//首先需要设置相机的一些参数
Camera.Parameters parameters=mCamera.getParameters();
parameters.setPictureFormat(ImageFormat.JPEG);//设置拍照的格式
parameters.setPictureSize(800, 400);//设置拍得的图片的大小
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);//在预览时自动对焦(前提是相机支持自动对焦的)
mCamera.autoFocus(new Camera.AutoFocusCallback() {//开始相机的自动对焦

@Override
public void onAutoFocus(boolean success, Camera camera) {
//success代表当前对焦是否已经完全准确
if(success) {
//如果对焦准确就进行拍照
mCamera.takePicture(null, null, mPictureCallback);//最后一个参数是一个回调
}

}
});//获取最清晰的焦距之后再进行拍照
}
});
mHolder = mPreview.getHolder();
mHolder.addCallback(this);// 将当前的Activity作为回调设置给mHolder(因为实现了Callback接口)
}

@Override
protected void onResume() {
super.onResume();
if (mCamera == null) {
mCamera = getCamera();// 将mCamera的生命周期与此Activity的生命周期进行绑定,保证Camera使用的资源能正确的初始化
if (mHolder != null) {
setStartPreview(mCamera, mHolder);
}
}
}

@Override
protected void onPause() {
super.onPause();
releaseCamera();// 将mCamera的生命周期与此Activity的生命周期进行绑定,保证Camera使用的资源能正确的释放
}

/**
* 获取系统的Camera对象
*
* @return
*/
private Camera getCamera() {
// 注意:package android.graphics中的Camera是用来实现3D图形变换的
// android.hardware.Camera才是需要导入的,使用系统硬件的系统相机
Camera camera = null;
try {
camera = Camera.open();//初始化操作
} catch (Exception e) {
camera = null;// 释放掉原来的对象引用,使之变成可回收的
e.printStackTrace();
}
return camera;
}

/**
* 开始预览相机内容
*/
private void setStartPreview(Camera camera, SurfaceHolder holder) {
// 需要将Camera对象与SurfaceView进行绑定,使得Camera实时预览的效果直接展现在SurfaceView上
try {
camera.setPreviewDisplay(holder);

// 需要注意,系统默认的Camera是横屏的,其预览的图像也是横屏的,因此需要将Camera预览角度进行转换
camera.setDisplayOrientation(90);// 将整个Camera旋转90°

camera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}

/**
* 释放相机占用的资源,解除相关的绑定
*/
private void releaseCamera() {
if(mCamera!=null) {
mCamera.setPreviewCallback(null);//将相机的回调置空,取消mPreview与mCamera的关联操作
mCamera.stopPreview(); //停止相机的取景功能
mCamera.release();
mCamera = null;
}
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
setStartPreview(mCamera, mHolder);//将surfaceCreated与setStartPreview进行绑定
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
mCamera.stopPreview();//将相机进行关闭
//然后重启预览功能
setStartPreview(mCamera, mHolder);
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
releaseCamera();
}
}


三、显示拍得的照片

1.布局文件

<?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" >

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Capture result"
android:gravity="center"
android:textSize="30sp"/>

<ImageView
android:id="@+id/resultImageView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>


2.Result .java

public class Result extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.result);
ImageView iv =(ImageView) findViewById(R.id.resultImageView);
String path=getIntent().getStringExtra("picPath");

//      Bitmap bitmap = BitmapFactory.decodeFile(path);
//      iv.setImageBitmap(bitmap);

//直接从指定路径获得图片,但是由于在CameraCuston中改变了预览的角度,但是拍照得到的照片依旧是横置的
//所以在这里如果不加处理,显示的照片就会是横置的,以下为处理方法
FileInputStream fis = null;
try {

fis = new FileInputStream(path);
Bitmap bitmap = BitmapFactory.decodeStream(fis);
Matrix matrix = new Matrix();
matrix.setRotate(90);//选择90°
bitmap = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix, true);//通过变换矩阵得到新的bitmap

//根据的实际的手机,还是需要考录是否缩小图片
//          BitmapFactory.Options options=new BitmapFactory.Options();
//          options.inJustDecodeBounds=false;//如果为true,bitmap将会为null
//          options.inSampleSize=2;//把图片的尺寸缩小一半
//          Bitmap bitmap = BitmapFactory.decodeStream(fis,null,options); //在CustomCamera已经设置过照片的大小
iv.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}


四、修改AndroidManifest.xml文件,添加相应权限,注册新增的Activity

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.cameratest"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="17" />

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

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

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

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

</application>

</manifest>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: