转载请注明出处amoscxy的博客:https://mp.youkuaiyun.com/mdeditor/79117522
一 调用系统相机
(1)调用系统相机是用过滤规则匹配的方式,系统相机设置了 规则,因此调用相机秩序action匹配:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivity(intent);
(2)想要获取拍照图片,可以通过startActivityForResult … onActivityResult来实现
public void aCamera(View view) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, REQ_1);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == REQ_1) {
if (data != null) {
Bundle bundle = data.getExtras();
Bitmap bitmap = (Bitmap) bundle.get("data");
mImageView.setImageBitmap(bitmap);
}
}
}
}
需要注意的是,为防止图片太大,导致内存溢出,bundle.get(“data”)返回的图片只是缩略图,质量比较差,要想通过系统相机获得拍照原图,需要通过intent.putExtra(MediaStore.EXTRA_OUTPUT,photoUri);
修改系统相机拍照图片保存的路径,再从路径获取原图。
public void aCamera2(View view) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri photoUri = Uri.fromFile(new File(mFilePath));
intent.putExtra(MediaStore.EXTRA_OUTPUT,photoUri);
startActivityForResult(intent, REQ_2);
}
mFIlePath最好是sd卡中的目录,如:mFilePath = Environment.getExternalStorageDirectory().getPath() + "/" + System.currentTimeMillis() + ".png";
,要将图片保存到sd卡上需要读写权限
可以通过文件流读写方式获取图片流,并转换成图片:
FileInputStream fis = new FileInputStream(mFilePath);
Bitmap bitmap = BitmapFactory.decodeStream(fis);
此处得到的图片bitmap是拍照的原图。
具体为:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
...
if(requestCode == REQ_2){
FileInputStream fis = null;
try {
fis = new FileInputStream(mFilePath);
Bitmap bitmap = BitmapFactory.decodeStream(fis);
mImageView.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
大部分时候系统相机不能满足我们的需求,因此掌握自定义相机是很必要的
二 自定义相机
需要完成三步:
(1)通过Camera.open()
获取相机(Camera)对象,
/**
* 获取Camera对象
* @return
*/
private Camera getCamera(){
Camera camera;
try {
camera = Camera.open();
} catch (Exception e) {
camera = null;
e.printStackTrace();
}
return camera;
}
(2)通过camera.setPreviewDisplay(holder)
,将Camera与SurfaceHolder进行绑定,开始预览相机内容,
/**
* 开始预览相机内容
*/
private void setStartPreview(Camera camera,SurfaceHolder holder){
try {
// 将Camera与SurfaceHolder进行绑定
camera.setPreviewDisplay(holder);
// 将系统Camera预览角度进行调整(默认预览是横屏的)
camera.setDisplayOrientation(90);
// 开始预览
camera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
(3)释放相机资源
/**
* 释放相机资源
*/
private void releaseCamera(){
if(mCamera != null){
mCamera.setPreviewCallback(null); // 将相机的回调置空
try {
mCamera.setPreviewDisplay(null); // 取消Camera与SurfaceHolder的关联
} catch (IOException e) {
e.printStackTrace();
}
mCamera.stopPreview(); // 取消相机取景功能
mCamera.release(); // 释放相机占用的系统资源
mCamera = null;
}
}
由于相机是系统持有的资源,因此以上三个步骤需要与Activity的生命周期onResume()和onPause()进行绑定:
@Override
protected void onResume() {
super.onResume();
if(mCamera == null){
mCamera = getCamera(); // 获取Camera对象
if(mHolder != null){
setStartPreview(mCamera,mHolder); // 开始预览相机内容
}
}
}
@Override
protected void onPause() {
super.onPause();
releaseCamera(); // 释放相机资源
}
注意要用SurfaceView来实现相机的预览功能,并通过SurfaceHolder来对SurfaceView进行管理:
实现SurfaceHolder.Callback接口,来对相机预览进行回调,
SurfaceView mPreview = findViewById(R.id.preview);
SurfaceHolder mHolder = mPreview.getHolder();
mHolder.addCallback(this);
实现回调的三个方法:
// 开始预览是调用
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
setStartPreview(mCamera,mHolder); // 开始预览
}
// 预览改变是调用
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
mCamera.stopPreview(); // 停止预览
setStartPreview(mCamera,mHolder); // 开始预览
}
// 预览结束时调用
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
releaseCamera(); // 释放相机资源
}
实现自定义相机的拍照功能:
与我们拿着单反拍照时要设置光圈、快门等相同,自定义相机拍照前也要通过Camera.Parameters
的各种set***
方法设置拍照参数:
/**
* 实现拍照功能
* @param view
*/
public void capture(View view){
// 拍照前要对Camera进行参数设置
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPictureFormat(ImageFormat.JPEG); // 设置拍照的模式
parameters.setPreviewSize(800,400); // 设置预览大小
if(parameters.getFocusMode().contains(Camera.Parameters.FOCUS_MODE_AUTO)){
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); // 设置为自动对焦
}
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean b, Camera camera) {
if(b){ // 对焦完全准确
mCamera.takePicture(null,null,mPictureCallback);
}
}
});
}
完全对焦后就开始拍照,mPictureCallback
是拍照回调借口的实现:
private Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] bytes, Camera camera) {
File tempFile = new File(filePath);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(tempFile);
fos.write(bytes);
fos.flush();
Intent intent = new Intent(CustomCamera.this,ResultActivity.class);
intent.putExtra("picPath",tempFile.getPath());
startActivity(intent);
CustomCamera.this.finish();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
filePath最好设置成sd卡的路径,
private String filePath = Environment.getExternalStorageDirectory().getPath() + "/" + System.currentTimeMillis() + ".png";
此处要对sd卡进行读写操作,因此要获取sd卡的读写权限
另外调用系统相机不需要获取相机权限,但自定义相机需要获取系统相机权限
由于预览时对相机进行了90度旋转,因此拍照回调获得的图片也进行了90度翻转,要获得正立的图片需要通过Matrix类的matrix.setRotate(90)
对回调图片(Bitmap)进行90旋转
Matrix matrix = new Matrix();
matrix.setRotate(90);
bitmap = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);
转载请注明出处amoscxy的博客:https://mp.youkuaiyun.com/mdeditor/79117522