preface

CameraX is a new library for Jetpack. This library makes it easier to add camera functionality to your application. The library provides a number of compatibility fixes and stop-gap workarounds to help create a consistent developer experience across multiple devices.

The development and use of a camera function has always been a hassle, involving various device adaptation issues, need to add a bunch of device-specific code in the code. Officials may also be aware of the problem, as Camerax is a library designed to make development easier. Claim: With CameraX, developers can achieve the same camera experience and functionality as pre-installed camera apps with just two lines of code.

Here is the effect picture:

use

Basic configuration

  1. Add a code base to your project’s build.gradle: Google ()
allprojects {
    repositories {
        ...
        google()
    }
}
Copy the code
  1. Configure build.gradle in module
android { ... compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } // For Kotlin projects kotlinOptions {jvmTarget = "1.8"}}Copy the code
  1. Adding library references
Def camera_version = "1.1.0-alpha11" // The following line is optional, as the core library is included indirectly by camera-camera2 implementation("androidx.camera:camera-core:${camera_version}") implementation("androidx.camera:camera-camera2:${camera_version}") // If you want to additionally use the CameraX Lifecycle library implementation("androidx.camera:camera-lifecycle:${camera_version}") // If you want to additionally Use the CameraX View class implementation(" Androidx. camera: Camera-View :1.0.0-alpha31") // If you want to additionally Use the CameraX Extensions Library implementation(" Androidx. camera: Camera-extensions :1.0.0-alpha31")Copy the code

After the above configuration, you can use the functions of camerax library normally. Here are some of the current version information:

1.0.2 stable compileSdk 1.0.2 stable compileSdk 1.0.2 stable compileSdk 1.0.2 stable compileSdk 1.0.2 stable compileSdk 1.0.2 stable compileSdk 1.0.2 stable compileSdk 1.0.2 stable compileSdk 1.0.2 stable compileSdk 1.0.2 stable compileSdk 1.0.2 stable compileSdk 1.0.2 stable compileSdk 1.0.2

There are two ways to handle this:

  • Configure our version of compileSdk to 30 or below
  • Use version 1.1.0- Alpha11

Achieve preview effect

  1. If you want to save an image to a folder, you may also need an additional WRITE_EXTERNAL_STORAGE permission, but this is beyond the scope of our discussion
private fun checkPermission() { if (ContextCompat.checkSelfPermission( this, Manifest.permission.CAMERA ) ! = PackageManager.PERMISSION_GRANTED ) { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), REQ_CAMERA) } else { initCamera() } }Copy the code
  1. Customize the Application and configure the CameraxConfig.provider
class CameraXApplication : Application(), CameraXConfig.Provider { override fun getCameraXConfig(): CameraXConfig { return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig()) .setMinimumLoggingLevel(Log.ERROR) .build(); }}Copy the code
  1. Add PreviewView to layout for photo preview display
<androidx.camera.view.PreviewView
    android:id="@+id/preview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent" />
Copy the code
  1. Create Preview and bind PreviewView to Preview
previewView = findViewById(R.id.preview)
preview = Preview.Builder().build()
preview.setSurfaceProvider(previewView.surfaceProvider)
Copy the code
  1. Get CameraProvider
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener(Runnable {
    cameraProvider = cameraProviderFuture.get()
    setupCamera()
}, ContextCompat.getMainExecutor(this))
Copy the code
  1. Select the camera through CameraSeletor and bind to the life cycle through The CameraProvider
cameraProvider? .let { cameraProvider.unbindAll() val cameraSelector = CameraSelector.Builder() .requireLensFacing(CameraSelector.LENS_FACING_BACK) .build() cameraProvider.bindToLifecycle( this as LifecycleOwner, cameraSelector, imageCapture, imageAnalysis, preview ) }Copy the code

At this point, we have a normal preview. It looks like a lot of flow, but the whole process is universal

Taking pictures

ImageCapture provides the takePicture interface, we can achieve the function of taking pictures ~

  1. Get ImageCapture
imageCapture =
    ImageCapture.Builder().setTargetRotation(previewView.display.rotation).build()
Copy the code
  1. Bind Capture to the lifecycle
cameraProvider.bindToLifecycle(
    this as LifecycleOwner,
    cameraSelector,
    imageCapture,
    imageAnalysis,
    preview
)
Copy the code
  1. Call takePicture to take a picture

Add a photo button to the layout to trigger a photo

<Button android:id="@+id/take_pic" android:layout_width="150dp" android:layout_height="45dp" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="10dp" Android :text=" photo "/> imageCapture? .takePicture( outputFileOption, ContextCompat.getMainExecutor(this as Context), object : ImageCapture.OnImageSavedCallback { override fun onError(error: ImageCaptureException) {toast.makeText (this@MainActivity, "There was a photo error ", Toast.LENGTH_SHORT).show() } override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) { Toast.makeText( this@MainActivity, outputFileResults.savedUri.toString(), Toast.LENGTH_SHORT ).show() } })Copy the code

The OnImageSavedCallback callback contains two functions: onImageSaved, onImageSaved, onError. When successful, the URI to save the image is obtained using the outputFileResults parameter

Front and rear camera switching

As mentioned in the previous section, select the camera through the Camera Elector and bind it to the lifecycle. Take a look at the requireLensFacing function of cameraSelector

Requires a camera with the specified lens facing.
Valid values for lens facing are LENS_FACING_FRONT and LENS_FACING_BACK.
If lens facing is already set, this will add extra requirement for lens facing instead of replacing the previous setting.
@NonNull
public Builder requireLensFacing(@LensFacing int lensFacing) {
    mCameraFilterSet.add(new LensFacingCameraFilter(lensFacing));
    return this;
}
Copy the code

Next add buttons in the layout to switch between front and rear cameras

<Button android:id="@+id/toggle_camera" android:layout_width="45dp" android:layout_height="45dp" android:layout_alignParentRight="true" android:layout_alignParentBottom="true" android:layout_marginRight="10dp" android:layout_marginBottom="10dp" android:background="@android:drawable/ic_menu_camera" /> toggleCamera.setOnClickListener { isBackCamera = ! isBackCamera setupCamera() } private fun setupCamera() { cameraProvider? .let { cameraProvider.unbindAll() val cameraSelector = CameraSelector.Builder() .requireLensFacing(if (isBackCamera) CameraSelector.LENS_FACING_BACK else CameraSelector.LENS_FACING_FRONT) .build() cameraProvider.bindToLifecycle( this as LifecycleOwner, cameraSelector, imageCapture, imageAnalysis, preview ) } }Copy the code

By resetting the cameraSelector, you can switch between before and after previews

Other parameter Settings: forward image flipping problem

When you switch to the front camera and take a picture, you will find that the image and the preview effect is the mirror flip. How to solve this problem? In fact, when we call ImageCapture takePicture, need to pass a ImageCapture OutputFileOptions parameters, we can configure the parameters of rotation of the image.

OutputFileOptions contains a Metadata parameter. See the API documentation

@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java public static final class Metadata { /** * Indicates a left-right mirroring (reflection). * * <p>The reflection is meant to be applied to the upright image (after rotation to the * target orientation). When saving the image to file, it is combined with the rotation * degrees, to generate the corresponding EXIF orientation value. */ private boolean mIsReversedHorizontal; /** * Whether the mIsReversedHorizontal has been set by the app explicitly. */ private boolean mIsReversedHorizontalSet = false; /** * Indicates an upside down mirroring, equivalent to a horizontal mirroring (reflection) * followed by a 180 degree rotation. * * <p>The reflection is meant to  be applied to the upright image (after rotation to the * target orientation). When saving the image to file, it is combined with the rotation * degrees, to generate the corresponding EXIF orientation value. */ private boolean mIsReversedVertical;Copy the code

Isn’t the mIsReversedHorizontal parameter just what we need? Therefore, we can determine whether the current photo is taken by the front camera and adjust this parameter

val metadata = ImageCapture.Metadata() metadata.isReversedHorizontal = ! isBackCamera val outputFileOption = ImageCapture.OutputFileOptions.Builder(File(savePath)).setMetadata(metadata).build()  imageCapture? .takePicture( outputFileOption, ContextCompat.getMainExecutor(this as Context), object : ImageCapture.OnImageSavedCallback { override fun onError(error: ImageCaptureException) { } override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) { } })Copy the code

See how the photo looks

Here for convenience, direct reference glide picture loading display

Implementation 'com. Making. Bumptech. Glide: glide: 4.12.0' val path: String? = intent.getStringExtra(PREVIEW_PATH) preview = findViewById(R.id.preview) path? .let { val uri = Uri.parse(path) Glide.with(this) .load(uri) .apply(RequestOptions.fitCenterTransform()) .into(preview) }Copy the code

conclusion

This is just a brief introduction to the basic use of the Camerax library. The library provides more than just a few functions, for example

  • ImageAnalysis: ImageAnalysis
  • Picture rotation correction
  • Extensions API: Out of focus imaging, face photo repair, HDR (high dynamic range) and more

Of course, through trial and error, we can achieve a powerful camera app through the Camerax library, which will be added later.

Finally, the demo address is attached: gitee-Demo