关于自定义相机的一些理解
2019-07-25 本文已影响0人
LiChengZe_Blog
前言
给自己做做笔记,加深印象,也算是复习,为了面试...
目录
一:调用系统相机
- 一:调用系统相机
- 1.权限
- 2.拍照
- 设置隐式意图,直接拍照,的到的是缩略图
- 设置隐式意图,保存原图片,得到的是原图
- 二:自定义相机
- 1.相机API相关类和接口
- 2.开发过程
- 3.示例代码
1.权限
<!-- 增加文件存储和访问摄像头的权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
如果是6.0的手机需要动态获取权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
//申请WRITE_EXTERNAL_STORAGE权限
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.CAMERA},
0);//自定义的code
}
2.拍照
(1)设置隐式意图,直接拍照,的到的是缩略图
public void btnclick(View view) {
Intent getImageByCamera = new Intent("android.media.action.IMAGE_CAPTURE");
startActivityForResult(getImageByCamera, 0);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0) {
Bundle extras = data.getExtras();
Bitmap bitmap = (Bitmap) extras.get("data");
img1.setImageBitmap(bitmap);
textView1.setText("width--->" + bitmap.getWidth() + "\n" + "height--->" + bitmap.getHeight() + "\n" + "byte--->" + bitmap.getByteCount() / 1024);
}
}
image图片大小
(2)设置隐式意图,保存原图片,得到的是原图
public void btnclick1(View view) {
mFilePath = Environment.getExternalStorageDirectory().getPath() + File.separator + "allens.png";
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri uri = Uri.fromFile(new File(mFilePath));
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(intent, 1);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1) {
try {
mFis = new FileInputStream(mFilePath);
Bitmap bitmap = BitmapFactory.decodeStream(mFis);
img2.setImageBitmap(bitmap);
textView2.setText("width--->" + bitmap.getWidth() + "\n" + "height--->" + bitmap.getHeight() + "\n" + "byte--->" + bitmap.getByteCount() / 1024);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (mFis != null)
mFis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
image图片大小
二:自定义相机
1.相机API相关类和接口
(1)相机
最主要的类,用于管理和操作相机资源。它提供了完整的相机底层接口,支持相机资源切换,设置预览/拍摄尺寸,设定光圈,曝光,聚焦等相关参数,获取预览/拍摄帧数据等功能重要方法如下:
方法 | 说明 |
---|---|
打开() | 获取摄像头实例。 |
setPreviewDisplay(SurfaceHolder) | 绑定绘制预览图像的表面。 |
setPrameters | 设置相机参数,包括前后摄像头,闪光灯模式,聚焦模式,预览和拍照尺寸等 |
startPreview() | 开始预览,将照相机底层硬件传来的预览帧数据显示在绑定的表面上。 |
stopPreview() | 停止预览,关闭CAMRA底层的帧数据传递以及表面上的绘制。 |
发布() | 释放相机实例 |
takePicture(Camera.ShutterCallback快门,Camera.PictureCallback raw,Camera.PictureCallback jpeg) | 这个是实现相机拍照的主要方法,包含了三个回调参数.shutter是快门按下时的回调,原料是获取拍照原始数据的回调,JPEG是获取经过压缩成JPG格式的图像数据的回调。 |
表面解释说明
surface是指向屏幕窗口原始图像缓冲区(raw buffer)的一个句柄,通过它可以获得这个屏幕上对应的画布,进而完成在屏幕上绘制查看的工作。通过surfaceHolder可以将Camera和surface连接起来,当相机和表面连接后,照相机获得的预览帧数据就可以通过表面显示在屏幕上了。
(2)SurfaceView
自定义相机的预览图像由于对更新速度和帧率要求比较高,所以比较适合用surfaceview来显示。
(3)SurfaceHolder
surfaceholder是控制的一个抽象接口,它能够表面控制表面的尺寸和格式,修改表面的像素,监视表面的变化等等
(4)SurfaceHolder.Callback接口
接口 | 说明 |
---|---|
surfaceCreated(SurfaceHolder holder) | 在表面创建后立即被调用。在开发自定义相机时,可以通过重载这个函数调用camera.open(),camera.setPreviewDisplay(),来实现获取相机资源,连接相机和表面等操作。 |
surfaceChanged(SurfaceHolder holder,int format,int width,int height) | 在表面发生格式或大小变化时调用。在开发自定义相机时,可以通过重载这个函数调用camera.startPreview来开启相机预览,使得相机预览帧数据可以传递给表面,从而实时显示相机预览图像。 |
surfaceDestroyed(SurfaceHolder holder) | 在表面销毁之前被调用。在开发自定义相机时,可以通过重载这个函数调用camera.stopPreview(),camera.release()来实现停止相机预览及释放相机资源等操作。 |
2.开发过程
- 检测和访问相机资源检查手机是否存在相机资源,如果存在,请求访问相机资源。
- 创建预览类创建继承自SurfaceView并实现SurfaceHolder接口的拍摄预览类。此类能够显示相机的实时预览图像。
- 建立预览布局有了拍摄预览类,即可创建一个布局文件,将预览画面与设计好的用户界面控件融合在一起。
- 设置拍照监听器给用户界面控件绑定监听器,使其能响应用户操作(如按下按钮),开始拍照过程。
- 拍照并保存文件将拍摄获得的图像转换成位图文件,最终输出保存成各种常用格式的图片。
3.示例代码
- 检测和访问相机资源检查手机是否存在相机资源,如果存在,请求访问相机资源。
boolean b = getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
- 创建预览类创建继承自SurfaceView并实现SurfaceHolder接口的拍摄预览类。此类能够显示相机的实时预览图像。
package com.spsc.myapplication;
import android.content.Context;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.hardware.Camera;
import java.io.IOException;
/**
* Created by allens on 2017/3/15.
*/
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(Context context, Camera camera) {
super(context);
//初始化Camera对象
mCamera = camera;
//得到SurfaceHolder对象
mHolder = getHolder();
//添加回调,得到Surface的三个声明周期方法
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
//设置预览方向
mCamera.setDisplayOrientation(90);
//把这个预览效果展示在SurfaceView上面
mCamera.setPreviewDisplay(holder);
//开启预览效果
mCamera.startPreview();
} catch (IOException e) {
// Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (holder.getSurface() == null) {
return;
}
//停止预览效果
mCamera.stopPreview();
//重新设置预览效果
try {
mCamera.setPreviewDisplay(mHolder);
} catch (IOException e) {
e.printStackTrace();
}
mCamera.startPreview();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
- 建立预览布局有了拍摄预览类,即可创建一个布局文件,将预览画面与设计好的用户界面控件融合在一起
<FrameLayout
android:id="@+id/camera_preview"
android:layout_width="100dp"
android:layout_height="100dp" />
Camera open = Camera.open(); //初始化 Camera对象
CameraPreview mPreview = new CameraPreview(this, open);
FrameLayout camera_preview = (FrameLayout) findViewById(R.id.camera_preview);
camera_preview.addView(mPreview);
- 设置拍照监听器给用户界面控件绑定监听器,使其能响应用户操作(如按下按钮),开始拍照过程。
@OnClick(R.id.btn_take_picture)
public void onClick() {
//得到照相机的参数
Camera.Parameters parameters = mCamera.getParameters();
//图片的格式
parameters.setPictureFormat(ImageFormat.JPEG);
//预览的大小是多少
parameters.setPreviewSize(800, 400);
//设置对焦模式,自动对焦
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
//对焦成功后,自动拍照
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
if (success) {
//获取照片
mCamera.takePicture(null, null, mPictureCallback);
}
}
});
}
//获取照片中的接口回调
Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
FileOutputStream fos = null;
String mFilePath = Environment.getExternalStorageDirectory().getPath() + File.separator + "tt001.png";
//文件
File tempFile = new File(mFilePath);
try {
//
fos = new FileOutputStream(tempFile);
fos.write(data);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//实现连续拍多张的效果
// mCamera.startPreview();
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
};
- 释放资源
if (mCamera != null) {
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;