Android Custom Camera to Realize Photographing Function
- 2021-09-11 21:27:22
- OfStack
This paper records the simple photo-taking function realized by custom Camera.
The Camera class is not recommended after 5.0. Instead, the class under the android. hardware. camera2 package is used in this article, Camera.
We first customize an View to inherit 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();
// Object supported by the camera PictureSize List
List<Camera.Size> pictureSizeList = parameters.getSupportedPictureSizes();
/** Select the appropriate resolution from the list */
Camera.Size picSize = getProperSize(pictureSizeList, ((float) height / width));
if (null == picSize) {
picSize = parameters.getPictureSize();
}
// According to the selected PictureSize Reset SurfaceView Size
float w = picSize.width;
float h = picSize.height;
parameters.setPictureSize(picSize.width, picSize.height);
this.setLayoutParams(new RelativeLayout.LayoutParams((int) (height * (h / w)), height));
// Object supported by the camera PreviewSize List
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); // Setting photo quality
if (parameters.getSupportedFocusModes().contains(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// Continuous focusing mode
}
mCamera.setDisplayOrientation(90);// Settings PreviewDisplay The effect is how many degrees to rotate the captured picture
mCamera.setParameters(parameters);
}
/**
* Choose the right resolution
*/
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) {// Default w:h = 4:3
result = size;
break;
}
}
}
return result;
}
}
The code is not difficult, when View is created, complete the initialization of Camera, then set the parameters of Camera (picture size, quality, etc.), and finally don't forget to release the resources when View is destroyed.
After the control is defined, we will use it and add OK to the layout file:
<?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>
Then complete the photo function in 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;
// Callback of photo shutter
private Camera.ShutterCallback mShutterCallback = new Camera.ShutterCallback() {
@Override
public void onShutter() {
}
};
// Callback to return the original data after taking pictures
private Camera.PictureCallback rawPictureCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
}
};
// Callback to return compressed data after taking pictures
private Camera.PictureCallback jpegPictureCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
mCameraSurfaceView.startPreview();
saveFile(data);
Toast.makeText(CameraActivity.this, " Successful photographing ", 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);
}
}
// Save pictures to hard disk
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();
}
}
}
}
Finally, remember to add photo and disk operation permissions:
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
By this very simple photo Demo, it can only be used as Demo, and there is still a long way to go before it is officially used. Please record it again.
Download: Source code