CameraX(1.0.0-alpha06)上的takePicture需要执行程序

时间:2019-10-14 09:35:53

标签: android androidx android-camerax

更新后
androidx.camera:camera-core:1.0.0-alpha03

androidx.camera:camera-core:1.0.0-alpha06

setTargetAspectRatio(在ImageCaptureConfig.Builder中)和takePicture(在ImageCapture中)的签名已更改。

网络上的官方文档和信息没有显示如何使用新方法(如何指定执行程序)。

更新后损坏的代码:

...
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?) {
            ...
        })
    }
}

有人有(或知道在哪里找到)如何使用新方法的示例吗? 预先感谢

7 个答案:

答案 0 :(得分:8)

显然最近已更新的官方Google Codelabs使用:Executors.newSingleThreadExecutor()

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

编辑:由于@kos的回复对我也很有意义,因此我添加了以下两个Android官方文档参考:

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

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

这样,本主题的每个读者都可以对执行者下定决心。

进一步编辑:自1.0.0-alpha07以来,API进行了重要的更改,因此我研究了一些文档。 GitHub示例显示了执行者检索,例如mainExecutor = ContextCompat.getMainExecutor(requireContext())Source

如果你们中的某些人已经实现了CameraX并且工作正常,那么我一定会等待Android release notes推荐的beta版本

答案 1 :(得分:1)

我面对的和你面对的一样。我从我这边解决了。

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

输出为(当我在onImageSaved方法中打印日志时)

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

对我来说很好,请尝试一下。

答案 2 :(得分:1)

您可以这样做。

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

答案 3 :(得分:0)

以下是alpha06中的更改的更改日志:https://godbolt.org/z/H-3fOt

  • if (rendercount == 2) { // rendercount - i am incrementing whenever we send/receive message rendercount = 3; BotPostRender(); // calling my function after receiving welcome message. } 方法现在采用setTargetAspectRatio()AspectRatio值的4_3枚举。
  • 16_9方法采用takePicture() //可以根据您的情况/需要使用执行程序。例子是(file, metadata, executor, imageSavedListener)
  • 使用val executor = Executors.newSingleThreadExecutor()代替useCase.onPreviewOutputUpdateListener =

仅供参考:CameraX将于2019年12月进入测试版

答案 4 :(得分:0)

您只需要运行以下命令即可。

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

答案 5 :(得分:0)

在点击监听器内部调用此函数/方法:

    private fun saveImage(){

        val file = File(this.externalMediaDirs.first(), "${System.currentTimeMillis()}.jpg")
        val fileB = ImageCapture.OutputFileOptions.Builder(file).build()

        imageCapture.takePicture(fileB, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback {
            override fun onImageSaved(fileB: ImageCapture.OutputFileResults) {
                val msg = "${fileB.savedUri} - ${file.absolutePath} - ${file.toURI()}"
            }

            override fun onError(imageCaptureError: ImageCaptureException) {
                val msg = "Photo capture failed: ${imageCaptureError.toString()}"
            }
        })
    }

msg中的onImageSaved将包含以下内容:

null - /storage/emulated/0/Android/media/com.mua.camx/1607589430984.jpg - file:/storage/emulated/0/Android/media/com.mua.camx/1607589430984.jpg

答案 6 :(得分:-2)

CameraX提供了内置的执行器,并且可以按以下方式实现拍照:

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

它不使用文件保存图像,而是将图像保存为内存中的缓冲区。