In order to make it easier for us to use Camera, there is an official library called CameraView. However, the library has been Deprecated and Jetpack CameraX is officially recommended instead. This article introduces the use of CameraView and CameraX

CameraView

CameraView is designed to help developers quickly integrate Camera1 and Camera2 features, as illustrated in the following table:

API Level Camera API Preview View
9-13 Camera1 SurfaceView
14 to 20 Camera1 TextureView
21-23 Camera2 TextureView
24 Camera2 SurfaceView

The development process

CameraView definition

Defined in the XML

<com.google.android.cameraview.CameraView
    android:id="@+id/camera"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:keepScreenOn="true"
    android:adjustViewBounds="true"
    app:autoFocus="true"
    app:aspectRatio="4:3"
    app:facing="back"
    app:flash="auto"/>
Copy the code

In XML, you can configure:

  • AutoFocus: Indicates whether to autoFocus
  • AspectRatio: Indicates the scale of the preview screen
  • Facing: Front and rear cameras
  • Flash: flash mode

Increased life cycle

@Override
protected void onResume(a) {
    super.onResume();
    mCameraView.start();
}

@Override
protected void onPause(a) {
    mCameraView.stop();
    super.onPause();
}
Copy the code

Once declared, you are ready to preview

Camera status callback

Add a callback after CameraView is declared in XML

if(mCameraView ! =null) { mCameraView.addCallback(mCallback); }...private CameraView.Callback mCallback
            = new CameraView.Callback() {

    @Override
    public void onCameraOpened(CameraView cameraView) {
        Log.d(TAG, "onCameraOpened");
    }

    @Override
    public void onCameraClosed(CameraView cameraView) {
        Log.d(TAG, "onCameraClosed");
    }

    @Override
    public void onPictureTaken(CameraView cameraView, final byte[] data) {
        Log.d(TAG, "onPictureTaken " + data.length);
        Toast.makeText(cameraView.getContext(), R.string.picture_taken, Toast.LENGTH_SHORT)
                .show();
        getBackgroundHandler().post(new Runnable() {
            @Override
            public void run(a) {
                File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES),
                        "picture.jpg");
                Log.d(TAG, "onPictureTaken file path: " + file.getPath());
                OutputStream os = null;
                try {
                    os = new FileOutputStream(file);
                    os.write(data);
                    os.close();
                } catch (IOException e) {
                    Log.w(TAG, "Cannot write to " + file, e);
                } finally {
                    if(os ! =null) {
                        try {
                            os.close();
                        } catch (IOException e) {
                            // Ignore}}}}}); }};Copy the code

There are three callback methods, camera on, camera off, and photo.

Taking pictures

mCameraView.takePicture();
Copy the code

It’s as simple as that, click and take a picture, and then process the image data in the callback

CameraX

CameraX is a Jetpack support library designed to simplify Camera development. It is based on the Camera2 API and backward compatible to Android 5.0 (API level 21). It has the following features:

  • Easy to preview and take photos with just a few lines of code
  • Maintain device consistency. Aspect ratio, screen orientation, rotation, preview size, and high resolution image size all work well on different camera devices
  • Extension of camera features, adding portrait, HDR, night mode and beauty features

The development process

Library reference

The latest version of CameraX is 1.0.0-alpha06, which is referenced in build.gradle of app:

dependencies {
    // CameraX core library.
    def camerax_version = "1.0.0 - alpha06"
    implementation "androidx.camera:camera-core:${camerax_version}"
    // If you want to use Camera2 extensions.
    implementation "androidx.camera:camera-camera2:${camerax_version}"

    def camerax_view_version = "1.0.0 - alpha03"
    def camerax_ext_version = "1.0.0 - alpha03"
    //other
    // If you to use the Camera View class
    implementation "androidx.camera:camera-view:$camerax_view_version"
    // If you to use Camera Extensions
    implementation "androidx.camera:camera-extensions:$camerax_ext_version"
}
Copy the code

Because CameraX is a Jetpack support library, cameras are opened and released using Jetpack’s Lifecycle.

preview

Preview parameter Settings using previewConfig.builder () :

PreviewConfig config = new PreviewConfig.Builder()
                .setLensFacing(CameraX.LensFacing.BACK)
                .setTargetRotation(mTextureView.getDisplay().getRotation())
                .setTargetResolution(new Size(640.480))
                .build();

Preview preview = new Preview(config);
preview.setOnPreviewOutputUpdateListener(new Preview.OnPreviewOutputUpdateListener() {
    @Override
    public void onUpdated(@NonNull Preview.PreviewOutput output) {
        if (mTextureView.getParent() instanceof ViewGroup) {
            ViewGroup viewGroup = (ViewGroup) mTextureView.getParent();
            viewGroup.removeView(mTextureView);
            viewGroup.addView(mTextureView, 0); mTextureView.setSurfaceTexture(output.getSurfaceTexture()); updateTransform(); }}});//lifecycle
CameraX.bindToLifecycle(this, preview);
Copy the code

Preivewconfig. Builder allows you to set a number of properties, including the camera, rotation direction, preview resolution, and many other options for you to experiment with. During the Preview callback listen, the SurfaceTexture of the output is set to mTextureView, the image preview is implemented, and finally the binding for Lifecycle is added.

Taking pictures

ImageCaptureConfig captureConfig = new ImageCaptureConfig.Builder()
        .setTargetAspectRatio(AspectRatio.RATIO_16_9)
        .setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
        .setTargetRotation(getWindowManager().getDefaultDisplay().getRotation())
        .build();

ImageCapture imageCapture = new ImageCapture(captureConfig);
mTakePicture.setOnClickListener((view) -> {
    final File file = new File(getExternalMediaDirs()[0], System.currentTimeMillis() + ".jpg");
    Log.d("DEBUG"."##### file path: " + file.getPath());
    imageCapture.takePicture(file, ContextCompat.getMainExecutor(getApplicationContext()), new ImageCapture.OnImageSavedListener() {
        @Override
        public void onImageSaved(@NonNull File file) {
            Log.d("DEBUG"."##### onImageSaved: " + file.getPath());
        }

        @Override
        public void onError(@NonNull ImageCapture.ImageCaptureError imageCaptureError, @NonNull String message, @Nullable Throwable cause) {
            Log.d("DEBUG"."##### onError: "+ message); }}); }); CameraX.bindToLifecycle(this, preview, imageCapture);
Copy the code

Pictures of parameters through ImageCaptureConfig. Builder set, here only set up the image aspect ratio, mode and direction of rotation, and there are many other ways, you can test by oneself. To actually call the photo method:

  • TakePicture (OnImageCapturedListener) : This method provides a memory buffer for the picture taken.
  • TakePicture (File, OnImageSavedListener) : This method saves the picture taken to the provided File location.
  • TakePicture (File, OnImageSavedListener, Metadata) : This method can be used to specify Metadata to be embedded in the Exif of a saved File.

The example calls takePicture(File, OnImageSavedListener) and saves it directly as a File. Finally, add the binding for Lifecycle.

Image analysis

ImageAnalysisConfig analysisConfig = new ImageAnalysisConfig.Builder()
        .setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE)
        .build();

ImageAnalysis imageAnalysis = new ImageAnalysis(analysisConfig);
imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(getApplicationContext()),
        new LuminosityAnalyzer());

CameraX.bindToLifecycle(this, preview, imageCapture, imageAnalysis); .private class LuminosityAnalyzer implements ImageAnalysis.Analyzer {
    private long lastAnalyzedTimestamp = 0L;

    @Override
    public void analyze(ImageProxy image, int rotationDegrees) {
        final Image img = image.getImage();
        if(img ! =null) {
            Log.d("DEBUG", img.getWidth() + ","+ img.getHeight()); }}}Copy the code

ImageAnalysis is not a necessary step, but ImageAnalysis can analyze each frame of the image. Set parameters via ImageAnalysisConfig. Builder (), here only set up ImageReaderMode, it has two modes:

  • Block mode (imagereadermode.acquire_next_image) : acquireNextImage() in Camera2, acquireNextImage(), obtains the next latest available Image
  • Unblocking mode (imagereadermode.acquire_latest_image) : acquireLatestImage() in Camera2 retrieves the latest image in the image queue and clears the queue to delete the existing old image

Finally, add the binding for Lifecycle. CameraX is also very simple to use. It takes only a few lines of code to package the complex apis of Camera2 into a unified config. The code covered in this article

reference

  • CameraX
  • Android Camera programming from entry to mastery
  • Introduction and practice of CameraX, a new component of Google Jetpack