前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android自定义Camera实现拍照功能

Android自定义Camera实现拍照功能

作者头像
砸漏
发布2020-11-05 10:36:07
9400
发布2020-11-05 10:36:07
举报
文章被收录于专栏:恩蓝脚本恩蓝脚本

本文记录了用自定义Camera实现的简单拍照功能。

Camera类在5.0以后不推荐使用了,取而代之的是android.hardware.camera2包下的类,本文使用Camera。 我们首先自定义一个View去继承SurfaceView:

代码语言:javascript
复制
public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Camera.AutoFocusCallback {
private SurfaceHolder mHolder;
private Camera mCamera;
private static final int ORIENTATION = 90;
private int mScreenWidth;
private int mScreenHeight;
private boolean isOpen;
public CameraSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
getScreenMatrix(context);
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
private void getScreenMatrix(Context context) {
WindowManager WM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
WM.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;
mScreenHeight = outMetrics.heightPixels;
}
public void takePicture(Camera.ShutterCallback mShutterCallback, Camera.PictureCallback rawPictureCallback, Camera.PictureCallback jpegPictureCallback) {
if (mCamera != null)
mCamera.takePicture(mShutterCallback, rawPictureCallback, jpegPictureCallback);
}
public void startPreview() {
mCamera.startPreview();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (!checkCameraHardware(getContext()))
return;
if (mCamera == null) {
isOpen = safeCameraOpen(Camera.CameraInfo.CAMERA_FACING_BACK);
}
if (!isOpen) {
return;
}
mCamera.setDisplayOrientation(ORIENTATION);
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mCamera != null) {
setCameraParams(mScreenWidth, mScreenHeight);
mCamera.startPreview();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
releaseCameraAndPreview();
}
private boolean safeCameraOpen(int id) {
boolean qOpened = false;
try {
releaseCameraAndPreview();
mCamera = Camera.open(id);
qOpened = (mCamera != null);
} catch (Exception e) {
e.printStackTrace();
}
return qOpened;
}
private void releaseCameraAndPreview() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
return true;
} else {
return false;
}
}
@Override
public void onAutoFocus(boolean success, Camera camera) {
}
private void setCameraParams(int width, int height) {
Camera.Parameters parameters = mCamera.getParameters();
// 获取摄像头支持的PictureSize列表
List<Camera.Size  pictureSizeList = parameters.getSupportedPictureSizes();
/**从列表中选取合适的分辨率*/
Camera.Size picSize = getProperSize(pictureSizeList, ((float) height / width));
if (null == picSize) {
picSize = parameters.getPictureSize();
}
// 根据选出的PictureSize重新设置SurfaceView大小
float w = picSize.width;
float h = picSize.height;
parameters.setPictureSize(picSize.width, picSize.height);
this.setLayoutParams(new RelativeLayout.LayoutParams((int) (height * (h / w)), height));
// 获取摄像头支持的PreviewSize列表
List<Camera.Size  previewSizeList = parameters.getSupportedPreviewSizes();
Camera.Size preSize = getProperSize(previewSizeList, ((float) height) / width);
if (null != preSize) {
parameters.setPreviewSize(preSize.width, preSize.height);
}
parameters.setJpegQuality(100); // 设置照片质量
if (parameters.getSupportedFocusModes().contains(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 连续对焦模式
}
mCamera.setDisplayOrientation(90);// 设置PreviewDisplay的方向,效果就是将捕获的画面旋转多少度显示
mCamera.setParameters(parameters);
}
/**
* 选取合适的分辨率
*/
private Camera.Size getProperSize(List<Camera.Size  pictureSizeList, float screenRatio) {
Camera.Size result = null;
for (Camera.Size size : pictureSizeList) {
float currentRatio = ((float) size.width) / size.height;
if (currentRatio - screenRatio == 0) {
result = size;
break;
}
}
if (null == result) {
for (Camera.Size size : pictureSizeList) {
float curRatio = ((float) size.width) / size.height;
if (curRatio == 4f / 3) {// 默认w:h = 4:3
result = size;
break;
}
}
}
return result;
}
}

代码没什么难度,在View创建的时候完成Camera的初始化,然后对Camera进行参数的设置(图片尺寸,质量之类的),最后别忘了在View销毁的时候对资源进行释放。

控件定义完了之后我们就要去使用它,在布局文件中添加就OK:

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"? 
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
<com.padoon.cameratest.CameraSurfaceView
android:id="@+id/sv_camera"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="4"/ 
<ImageView
android:id="@+id/img_take_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_gravity="bottom"
android:layout_marginBottom="10dp"
android:layout_marginRight="10dp"
android:src="@mipmap/icon_camera"/ 
</RelativeLayout 

然后在Activity中去完成拍照功能:

代码语言:javascript
复制
public class CameraActivity extends AppCompatActivity {
private boolean isClick = true;
private static final String PATH_IMAGES = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "easy_check";
private CameraSurfaceView mCameraSurfaceView;
//拍照快门的回调
private Camera.ShutterCallback mShutterCallback = new Camera.ShutterCallback() {
@Override
public void onShutter() {
}
};
//拍照完成之后返回原始数据的回调
private Camera.PictureCallback rawPictureCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
}
};
//拍照完成之后返回压缩数据的回调
private Camera.PictureCallback jpegPictureCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
mCameraSurfaceView.startPreview();
saveFile(data);
Toast.makeText(CameraActivity.this, "拍照成功", Toast.LENGTH_SHORT).show();
isClick = true;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView img_take_photo = (ImageView) findViewById(R.id.img_take_photo);
mCameraSurfaceView = (CameraSurfaceView) findViewById(R.id.sv_camera);
img_take_photo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
takePhoto();
}
});
}
public void takePhoto() {
if (isClick) {
isClick = false;
mCameraSurfaceView.takePicture(mShutterCallback, rawPictureCallback, jpegPictureCallback);
}
}
//保存图片到硬盘
public void saveFile(byte[] data) {
String fileName = UUID.randomUUID().toString() + ".jpg";
FileOutputStream outputStream = null;
try {
File file = new File(PATH_IMAGES);
if (!file.exists()) {
file.mkdirs();
}
outputStream = new FileOutputStream(PATH_IMAGES + File.separator + fileName);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
bufferedOutputStream.write(data, 0, data.length);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

最后记得添加拍照跟磁盘操作权限:

代码语言:javascript
复制
<uses-permission android:name="android.permission.CAMERA"/ 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/ 

到这一个非常简单的拍照Demo就完成了,只能当做Demo使用,离开发正式使用还有一段的距离,再次特地记录一下。

下载:源码

以上就是本文的全部内容,希望对大家的学习有所帮助。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-09-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档