takePicture require executor on CameraX (1.0.0-alpha06)

早过忘川 提交于 2019-12-23 09:17:11

问题


After update from

androidx.camera:camera-core:1.0.0-alpha03

to

androidx.camera:camera-core:1.0.0-alpha06

signatures of methods setTargetAspectRatio (in ImageCaptureConfig.Builder) and takePicture (in ImageCapture) have been changed.

Official documentation and info in web doesn't show how to use new methods (how to specify executor).

Code which broken after update:

...
val captureConfig = ImageCaptureConfig.Builder()
    .setTargetAspectRatioCustom(Rational(1, 1)) //this method changed
    .setFlashMode(flashMode)
    .setLensFacing(lensFacing)
    .build()

val capture = ImageCapture(captureConfig)

binding.takeAPhoto.setOnClickListener {
    ...
    val imageFile = createTempFile(System.currentTimeMillis().toString(), ".jpg")
    capture.takePicture(imageFile, object : ImageCapture.OnImageSavedListener { //this method also changed

        override fun onImageSaved(file: File) {
            ...
        }

        override fun onError(useCaseError: ImageCapture.UseCaseError, message: String, cause: Throwable?) {
            ...
        })
    }
}

Does anyone have (or know where to find) example of how to use new methods? Thanks in advance


回答1:


I faced same thing as you are facing. I resolved it from my side.

class MainActivity : AppCompatActivity(), Executor {
    private var right: Int = 0
    private var bottom: Int = 0
    private var left: Int = 0
    private var top: Int = 0
    private lateinit var preview: Preview
    private val REQUEST_CODE_PERMISSIONS = 10
    private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)
    private lateinit var imageCapture: ImageCapture
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        if (allPermissionsGranted()) {
            viewFinder.post { startCamera() }
        } else {
            ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)
        }

        viewFinder.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
            updateTransform()
        }

        buttonPlus.setOnClickListener {
            if (right < 100) {
                right += 100
                bottom += 100
                left += 100
                top += 100
                val my = Rect(left, top, right, bottom)
                preview.zoom(my)
            }
        }

        buttonMinus.setOnClickListener {
            if (right > 0) {
                right -= 100
                bottom -= 100
                left -= 100
                top -= 100
                val my = Rect(left, top, right, bottom)
                preview.zoom(my)
            }
        }
    }

    @SuppressLint("RestrictedApi")
    private fun startCamera() {
        val metrics = DisplayMetrics().also { viewFinder.display.getRealMetrics(it) }
        val screenAspectRatio = Rational(metrics.widthPixels, metrics.heightPixels)
        val previewConfig = PreviewConfig.Builder().apply {
            setTargetAspectRatioCustom(screenAspectRatio)
            setTargetRotation(viewFinder.display.rotation)
        }.build()
        preview = Preview(previewConfig)
        preview.setOnPreviewOutputUpdateListener {
            val parent = viewFinder.parent as ViewGroup
            parent.removeView(viewFinder)
            parent.addView(viewFinder, 0)
            viewFinder.surfaceTexture = it.surfaceTexture
            updateTransform()
        }
        CameraX.bindToLifecycle(this, preview)

        captureImage()
    }

    @SuppressLint("RestrictedApi")
    private fun captureImage() {
        val imageCaptureConfig = ImageCaptureConfig.Builder()
                .apply {
                    setTargetAspectRatioCustom(Rational(1, 1))
                    setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
                }.build()
        imageCapture = ImageCapture(imageCaptureConfig)
        CameraX.bindToLifecycle(this, imageCapture)
        capture_button.setOnClickListener {
            val file = File(this.externalMediaDirs.first(), "${System.currentTimeMillis()}.jpg")
            imageCapture.takePicture(file, this, object : ImageCapture.OnImageSavedListener {
                override fun onImageSaved(file: File) {
                    val msg = "Photo capture succeeded: ${file.absolutePath}"
                    Log.d("CameraXApp", msg)
                }

                override fun onError(imageCaptureError: ImageCapture.ImageCaptureError, message: String, cause: Throwable?) {
                    val msg = "Photo capture failed: $message"
                    Log.e("CameraXApp", msg)
                    cause?.printStackTrace()
                }
            })
        }
    }

    override fun execute(command: Runnable) {
        command.run()
    }

    private fun updateTransform() {
        val matrix = Matrix()
        val centerX = viewFinder.width / 2f
        val centerY = viewFinder.height / 2f
        val rotationDegrees = when (viewFinder.display.rotation) {
            Surface.ROTATION_0 -> 0
            Surface.ROTATION_90 -> 90
            Surface.ROTATION_180 -> 180
            Surface.ROTATION_270 -> 270
            else -> return
        }
        matrix.postRotate(-rotationDegrees.toFloat(), centerX, centerY)
        viewFinder.setTransform(matrix)
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        if (requestCode == REQUEST_CODE_PERMISSIONS) {
            if (allPermissionsGranted()) {
                viewFinder.post { startCamera() }
            } else {
                Toast.makeText(this, "Permissions not granted by the user.", Toast.LENGTH_SHORT).show()
                finish()
            }
        }
    }

    private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
        ContextCompat.checkSelfPermission(baseContext, it) == PackageManager.PERMISSION_GRANTED
    }


    override fun onDestroy() {
        super.onDestroy()
        imageCapture.let {
            CameraX.unbind(imageCapture)
        }
    }
}

And the output is (As I print log in onImageSaved method)

Photo capture succeeded: /storage/emulated/0/Android/media/com.akshay.cameraxzoominoutdemo/1571052301192.jpg

It's working fine for me, try out this.




回答2:


The official Google Codelabs which obviously have been updated recently use: Executors.newSingleThreadExecutor()

Reference: https://codelabs.developers.google.com/codelabs/camerax-getting-started/#4

Edit: Since @kos's response also makes sense to me, I've added these two official Android docs references:

https://developer.android.com/reference/java/util/concurrent/Executors.html#newSingleThreadExecutor()

https://developer.android.com/reference/java/util/concurrent/Executors.html#newCachedThreadPool()

This way every reader of this topic can make up his/her own mind with respect to executors.

FURTHER EDIT: There are crucial API changes since 1.0.0-alpha07 so I studied some of the docs. There's a GitHub sample showing executor retrieval like so mainExecutor = ContextCompat.getMainExecutor(requireContext())(Source)

If some of you already implemented CameraX and it works fine, I'd definitely wait for the beta release as recommended by Android's release notes




回答3:


You can do it like this.

imageCapture.takePicture(file, { it.run() }, object : ImageCapture.OnImageSavedListener {
    override fun onImageSaved(file: File) {}
    override fun onError(useCaseError: ImageCapture.ImageCaptureError, message: String, cause: Throwable?) {}
})



回答4:


Here is a change log for the changes in alpha06 : https://developer.android.com/jetpack/androidx/releases/camera

  • setTargetAspectRatio() method now takes AspectRatio enum with 4_3 or 16_9 value.
  • takePicture() method takes (file, metadata, executor, imageSavedListener) // could use executor as per your case/need. example is val executor = Executors.newSingleThreadExecutor()
  • instead of useCase.onPreviewOutputUpdateListener = use useCase.setOnPreviewOutputUpdateListener()

FYI : CameraX will be in Beta in Dec 2019




回答5:


You have to only run the command as below.

@Override
public void execute(Runnable command) {
    command.run(); // <-- THIS IS NEEDED
}



回答6:


CameraX provides with built-in executors and take picture can be implemented as below:

imgCaptureButton.setOnClickListener(new View.OnClickListener() {
    @Override
    @SuppressLint("RestrictedApi")
    public void onClick(View v) {
        imgCap.takePicture(CameraXExecutors.mainThreadExecutor(),new ImageCapture.OnImageCapturedListener() {
            @Override
            public void onCaptureSuccess(ImageProxy image, int rotationDegrees) {
                super.onCaptureSuccess(image, rotationDegrees);

                // Play with the Image here.
            }
        });
    }
});

It does not use File to save the image, instead saves the image as a buffer in the memory.



来源:https://stackoverflow.com/questions/58373986/takepicture-require-executor-on-camerax-1-0-0-alpha06

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!