软件编程
位置:首页>> 软件编程>> Android编程>> Android自定义Camera实现拍照功能

Android自定义Camera实现拍照功能

作者:忙碌的咖啡  发布时间:2021-09-22 09:18:58 

标签:Android,camera,拍照

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

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


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:


<?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中去完成拍照功能:

 


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();
  }
 }
}
}

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


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

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

下载:源码

来源:https://blog.csdn.net/ww55555577/article/details/62041140

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com